網(wǎng)絡(luò)爬蟲又稱為網(wǎng)頁蜘蛛、網(wǎng)絡(luò)機(jī)器人。網(wǎng)絡(luò)爬蟲是一種按照一定的規(guī)則自動(dòng)的抓取網(wǎng)絡(luò)信息的程序或者腳本。通俗的說,就是根據(jù)一定的算法實(shí)現(xiàn)編程開發(fā),主要通過URL實(shí)現(xiàn)數(shù)據(jù)的抓取和挖掘。
根據(jù)系統(tǒng)結(jié)構(gòu)和開發(fā)技術(shù)大致可分為4種類型:
(1)通用網(wǎng)絡(luò)爬蟲,又稱為全網(wǎng)爬蟲,常見的有百度,Google等。
(2)聚焦網(wǎng)絡(luò)爬蟲,又稱主題網(wǎng)絡(luò)爬蟲,是選擇性的爬行根據(jù)需求的主題相關(guān)頁面的網(wǎng)絡(luò)爬蟲。
(3)增量式網(wǎng)絡(luò)爬蟲。是指對(duì)已下載網(wǎng)頁采取增量式更新和只爬行新產(chǎn)生或者已經(jīng)發(fā)生變化的網(wǎng)頁的爬蟲,它能夠在一定程度上保證所爬行的頁面盡可能是新的頁面。只會(huì)在需要的時(shí)候爬行新產(chǎn)生或發(fā)生更新的頁面,并不重新下載沒有發(fā)生變化的頁面,這類爬蟲在實(shí)際中不太普及。
(4)深層網(wǎng)絡(luò)爬蟲。是大部分內(nèi)容不能通過靜態(tài)URL獲取的,隱藏在表單后的,只有用戶提交一些關(guān)鍵詞才能獲得的網(wǎng)絡(luò)頁面。
這四類大致又可以分為兩類,通用爬蟲和聚焦爬蟲。聚焦網(wǎng)絡(luò)爬蟲,增量式網(wǎng)絡(luò)爬蟲和深層網(wǎng)絡(luò)爬蟲可歸為一類,因?yàn)樗麄兪嵌ㄏ蚺老x數(shù)據(jù)。而通用爬蟲在網(wǎng)絡(luò)上稱為搜索引擎。
爬蟲的設(shè)計(jì)思路:
(1) 明確需要爬取的網(wǎng)頁的URL地址;
(2)通過http請(qǐng)求來獲取對(duì)應(yīng)的HTML頁面;
(3)提取HTML的內(nèi)容。若是有用的數(shù)據(jù),就保存起來;若是繼續(xù)爬取的頁面,就重新指定第(2)步。
http是一個(gè)簡(jiǎn)單的請(qǐng)求-響應(yīng)協(xié)議,它通常運(yùn)行在TCP之上。它指定了客戶端可能發(fā)送給服務(wù)器什么樣的消息以及得到什么樣的響應(yīng)??蛻舳耸墙K端用戶,服務(wù)器端是網(wǎng)站。通常使用web瀏覽器,網(wǎng)絡(luò)爬蟲或者其他工具,客戶端會(huì)發(fā)起一個(gè)到服務(wù)器上指定的http請(qǐng)求。這個(gè)客戶端就叫做用戶代理(User Agent)。一旦收到請(qǐng)求,服務(wù)器會(huì)發(fā)回一個(gè)狀態(tài)行(如“http/1.1 200 OK”)和 響應(yīng)的 消息,其中消息的內(nèi)容可能是請(qǐng)求的文件,錯(cuò)誤消息或者其他消息。
http協(xié)議傳輸?shù)臄?shù)據(jù)都是未加密的,因此使用http協(xié)議傳輸隱私信息非常不安全。
https協(xié)議傳輸?shù)臄?shù)據(jù)都是加密的。在傳輸數(shù)據(jù)之前需要客戶端與服務(wù)端之間進(jìn)行一次握手,在握手過程中將確立雙方加密傳輸數(shù)據(jù)的密碼信息。
請(qǐng)求頭描述客戶端向服務(wù)器發(fā)送請(qǐng)求時(shí)使用的協(xié)議類型,所使用的編碼以及發(fā)送內(nèi)容的長(zhǎng)度等。檢測(cè)請(qǐng)求頭是常見的反爬蟲策略。因?yàn)榉?wù)器會(huì)對(duì)請(qǐng)求頭做一次檢測(cè)來判斷此次請(qǐng)求是人為的還是非人為的。所以我們?cè)诿看伟l(fā)送請(qǐng)求時(shí)都添加上請(qǐng)求頭。
請(qǐng)求頭的參數(shù)如下:
(1)Accept:瀏覽器可以接收的類型
(2)Accept-Charset:編碼類型
(3)Accept-Encoding:可以接收壓縮編碼類型
(4)Accept-Language:可以接收的語言和國家類型
(5)Host:請(qǐng)求的主機(jī)地址和端口
(6)Referer:請(qǐng)求來自于那個(gè)頁面的URL
(7)User-Agent:瀏覽器相關(guān)信息
(8)Cookie:瀏覽器暫存服務(wù)器發(fā)送的信息
(9)Connection:http請(qǐng)求版本的特點(diǎn)
(10)Date:請(qǐng)求網(wǎng)站的時(shí)間
它是指某些網(wǎng)站為了辯護(hù)用戶身份,進(jìn)行session跟蹤而存儲(chǔ)在用戶本地終端上的數(shù)據(jù)。一個(gè)cookies就是存儲(chǔ)在用戶主機(jī)瀏覽器 的文本文件。
服務(wù)器可以利用cookies包含的信息判斷在http傳輸中的狀態(tài)。
JSON(JavaScript Object Notation, JS 對(duì)象簡(jiǎn)譜) 是一種輕量級(jí)的數(shù)據(jù)交換格式。它基于ECMAScript (歐洲計(jì)算機(jī)協(xié)會(huì)制定的js規(guī)范)的一個(gè)子集,采用完全獨(dú)立于編程語言的文本格式來存儲(chǔ)和表示數(shù)據(jù)。簡(jiǎn)潔和清晰的層次結(jié)構(gòu)使得 JSON 成為理想的數(shù)據(jù)交換語言。 易于人閱讀和編寫,同時(shí)也易于機(jī)器解析和生成,并有效地提升網(wǎng)絡(luò)傳輸效率。
例如:
{"name": "John Doe", "age": 18, "address": {"country" : "china", "zip-code": "10000"}}
JavaScript(簡(jiǎn)稱“JS”) 是一種具有函數(shù)優(yōu)先的輕量級(jí),解釋型或即時(shí)編譯型的高級(jí)編程語言。是一種解釋性腳本語言(代碼不進(jìn)行預(yù)編譯), 主要用來向HTML(標(biāo)準(zhǔn)通用標(biāo)記語言下的一個(gè)應(yīng)用)頁面添加交互行為。
JavaScript還能根據(jù)用戶觸發(fā)某些事件對(duì)用戶的操作進(jìn)行加工處理。要在爬蟲實(shí)現(xiàn)一些功能,就要分析JS如何執(zhí)行整個(gè)用戶登錄過程。
Fiddler是一個(gè)http協(xié)議調(diào)試代理工具,它能夠記錄并檢查所有你的電腦和互聯(lián)網(wǎng)之間的http通訊,設(shè)置斷點(diǎn),查看所有的“進(jìn)出”Fiddler的數(shù)據(jù)(指cookie,html,js,css等文件)。
在官網(wǎng)網(wǎng)站下載(https://www.telerik.com/download/fiddler),界面如下圖所示:
配置fiddler,使其能夠抓取https請(qǐng)求信息:
(1)打開菜單-tools-fidder options-https。
(2)勾選https中的選項(xiàng),然后點(diǎn)擊actions-trust root certificate,完成整數(shù)驗(yàn)證。
fiddler可通過同一無線網(wǎng)絡(luò)實(shí)現(xiàn)對(duì)手機(jī)應(yīng)用的抓包,手機(jī)抓包主要通過遠(yuǎn)程連接實(shí)現(xiàn)手機(jī)和fiddler通信。
實(shí)現(xiàn)fiddler抓取手機(jī)應(yīng)用的步驟如下:
(1)配置fiddler遠(yuǎn)程連接模式。打開菜單欄:tools--fiddler options--connections,把allow remote computers to connect勾選上。
(2)在手機(jī)端進(jìn)行參數(shù)配置。要連接在同一個(gè)IP地址上(cmd中輸入ipconfig查看IP地址)
(3)在手機(jī)瀏覽器中輸入電腦IP地址和fiddler端口,點(diǎn)擊確認(rèn)后跳轉(zhuǎn)到證書下載頁面,點(diǎn)擊下載fiddlerroot certificate.
(4)證書文件以cer為后綴名,完成證書安裝后,進(jìn)入手機(jī)當(dāng)前連接WiFi詳情,設(shè)置代理IP,主機(jī)名為電腦IP地址,端口為fiddler配置的端口。
在python3中不存在urllib2模塊,同一為urllib。urllib模塊有如下四個(gè)子模塊:
1 urllib.request:用來打開和讀取URL。 2 urllib.error:包含了urllib.request產(chǎn)生的異常。 3 urllib.parse:用來解析和處理URL。 4 urllib.robotparse:用于解析robots.txt文件。
urllib的方法及使用:
1 urllib.urlopen(url[, data[, proxies[,timeout[, context]]]]) 功能說明:urllib是用于訪問URL的唯一方法
參數(shù)解釋:
url :一個(gè)完整的遠(yuǎn)程資源路徑,一般是一個(gè)網(wǎng)站。 data:默認(rèn)值為none。若參數(shù)data為none,則代表請(qǐng)求方式為get,反之請(qǐng)求方式為post,發(fā)送post請(qǐng)求。參數(shù)data以字典形式存儲(chǔ)數(shù)據(jù),并將參數(shù)data由字典類型轉(zhuǎn)換成字節(jié)類型才能完成post請(qǐng)求。 proxies : 設(shè)置代理 timeout:超時(shí)設(shè)置 context:描述各種SSL選項(xiàng)的實(shí)例。
2 urllib.request.Request(url,data=none,headers={},method=none)
功能說明:聲明一個(gè)request對(duì)象,該對(duì)象可定義header等請(qǐng)求信息
參數(shù)解釋:
headers:設(shè)置request請(qǐng)求頭信息
method:設(shè)定請(qǐng)求方式,主要是get和post
"""urllib的使用"""
import urllib.request # 向指定URL發(fā)送請(qǐng)求,獲取響應(yīng)。 response = urllib.request.urlopen('http://httpbin.org/anything') # 獲取響應(yīng)內(nèi)容 content = response.read().decode('utf-8') print(content) print(type(response)) # 響應(yīng)碼 print(response.status) # 響應(yīng)頭信息 print(response.headers)
# 導(dǎo)入urllib import urllib.request url = 'https://movie.douban.com/' # 自定義請(qǐng)求頭 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)' 'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3', 'Referer': 'https://movie.douban.com/', 'Connection': 'keep-alive'} # 設(shè)置request的請(qǐng)求頭 req = urllib.request.Request(url, headers=headers) # 使用urlopen打開req html = urllib.request.urlopen(req).read().decode('utf-8') # 寫入文件 f = open('code2.txt', 'w', encoding='utf8') f.write(html) f.close()
requests模塊是在urllib的基礎(chǔ)上做了封裝,具備urllib的全部功能,讓使用者更加方便的使用。
安裝:pip install requests
有兩種方式:requests.get()和requests.post()方法
1 requests.get(url, params=none, **kwargs) 2 requests.post(url, data=none, json=none, **kwargs)
requests提供如下方法獲取響應(yīng)內(nèi)容:
1 r.status_code:響應(yīng)狀態(tài)碼(200表示訪問成功,4**表示失?。? 2 r.raw:原始響應(yīng)體,使用r.raw.read()讀取 3 r.content:字節(jié)方式的響應(yīng)體,需要進(jìn)行解碼 4 r.text:字符串方式的響應(yīng)體,會(huì)自動(dòng)根據(jù)響應(yīng)頭部的字符編碼進(jìn)行解碼 5 r.headers:以字典對(duì)象存儲(chǔ)服務(wù)器響應(yīng)頭,若鍵不存在,則返回none 6 r.json():requests中內(nèi)置的json解碼器 7 r.raise_for_status():請(qǐng)求失?。ǚ?00響應(yīng)),拋出異常 8 r.url:獲取請(qǐng)求鏈接 9 r.cookies:獲取請(qǐng)求后的cookies 10 r.encoding:獲取編碼格式
"""使用requests發(fā)送請(qǐng)求和攜帶參數(shù)""" import requests r = requests.get('https://httpbin.org/get') # 發(fā)送get請(qǐng)求 print(r.text) # 發(fā)送post請(qǐng)求,并帶參數(shù) r = requests.get('https://httpbin.org/get', params={'key1': 'value1', 'key2': 'value2'}) print(r.text) # 發(fā)送post請(qǐng)求,并傳遞參數(shù) r = requests.post('https://httpbin.org/post', data={'key': 'value'}) print(r.text) # 其他HTTP請(qǐng)求類型:PUT,DELETE,HEAD和OPTIONS r = requests.put('https://httpbin.org/put', data={'key': 'value'}) print(r.text) r = requests.delete('https://httpbin.org/delete') print(r.text) r = requests.head('https://httpbin.org/get') print(r.text) r = requests.options('https://httpbin.org/get') print(r.text)
(1)添加請(qǐng)求頭 import requests headers = { 'content-type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0'} requests.get("https://www.baidu.com/", headers=headers) (2)使用代理IP import requests proxies = { "http": "http://10.10.1.10:3128", "https": "http://10.10.1.10:1080", } requests.get("https://www.baidu.com/", proxies=proxies) (3)證書驗(yàn)證 import requests url = 'https://kyfw.12306.cn/otn/leftTicket/init' # 關(guān)閉證書驗(yàn)證 r = requests.get(url, verify=False) print(r.status_code) # 開啟證書驗(yàn)證 # r = requests.get(url, verify=True) # 設(shè)置證書所在路徑 # r = requests.get(url, verify= '/path/to/certfile') (4)超時(shí)設(shè)置 requests.get("https://www.baidu.com/", timeout=2) requests.post("https://www.baidu.com/", timeout=2) (5)使用cookies
import requests temp_cookies='JSESSIONID_GDS=y4p7osFr_IYV5Udyd6c1drWE8MeTpQn0Y58Tg8cCONVP020y2N!450649273;name=value' cookies_dict = {} for i in temp_cookies.split(';'): value = i.split('=') cookies_dict [value[0]] = value[1] r = requests.get(url, cookies=cookies) print(r.text)
若出現(xiàn)網(wǎng)絡(luò)問題,則請(qǐng)求將引發(fā)connectionerror異常。
若http請(qǐng)求返回不成功的狀態(tài)碼,則將會(huì)引發(fā)httperror異常。
若請(qǐng)求超時(shí),則會(huì)引起超時(shí)異常。
若請(qǐng)求超過配置的最大重定向數(shù),則會(huì)引發(fā)TooManyRedirects異常。
請(qǐng)求顯示引發(fā)的所有異常都繼承自requests.exceptions.RequestException。
正則表達(dá)式是對(duì)字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個(gè)“規(guī)則字符串”,這個(gè)“規(guī)則字符串”用來表達(dá)對(duì)字符串的一種過濾邏輯。
正則表達(dá)式是對(duì)字符串(包括普通字符(例如,a 到 z 之間的字母)和特殊字符(稱為“元字符”))操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個(gè)“規(guī)則字符串”,這個(gè)“規(guī)則字符串”用來表達(dá)對(duì)字符串的一種過濾邏輯。正則表達(dá)式是一種文本模式,該模式描述在搜索文本時(shí)要匹配的一個(gè)或多個(gè)字符串。
語法請(qǐng)參考:https://www.runoob.com/regexp/regexp-tutorial.html
4.3.1 模塊內(nèi)容
1. re.match(pattern, string[, flags])
這個(gè)方法將會(huì)從string(我們要匹配的字符串)的開頭開始,嘗試匹配pattern,一直向后匹配,如果遇到無法匹配的字符,立即返回None,如果匹配未結(jié)束已經(jīng)到達(dá)string的末尾,也會(huì)返回None。兩個(gè)結(jié)果均表示匹配失敗,否則匹配pattern成功,同時(shí)匹配終止,不再對(duì)string向后匹配。
"""match方法""" import re # match在起始位置匹配 ret = re.match('www', 'www.example.com') print(type(ret)) # 獲取匹配的內(nèi)容 print(ret.group()) # 獲取匹配內(nèi)容在原字符串里的下標(biāo) print(ret.span()) # 匹配不成功,返回None print(re.match('com', 'www.example.com')) line = "Cats are smarter than dogs" matchObj = re.match(r'(.*) are (.*?) .*', line, re.M | re.I) if matchObj: print("matchObj.group() : ", matchObj.group()) # 獲取第一組的內(nèi)容 print("matchObj.group(1) : ", matchObj.group(1)) print("matchObj.group(2) : ", matchObj.group(2)) else: print("No match!!")
參數(shù)說明: · pattern:匹配的正則表達(dá)式 · string:要匹配的字符串 · flags:標(biāo)志位,用于控制正則表達(dá)式的匹配方式,如是否區(qū)分大小寫,是否多行匹配等。 flags參數(shù)可選值: · re.I: 忽略大小寫(括號(hào)內(nèi)是完整寫法,下同) · re.M: 多行模式,改變'^'和'$'的行為(參見上圖) · re.S: 點(diǎn)任意匹配模式,改變'.'的行為 · re.L: 使預(yù)定字符類 \w \W \b \B \s \S 取決于當(dāng)前區(qū)域設(shè)定 · re.U: 使預(yù)定字符類 \w \W \b \B \s \S \d \D 取決于unicode定義的字符屬性 · re.X: 詳細(xì)模式。這個(gè)模式下正則表達(dá)式可以是多行,忽略空白字符,并可以加入注釋。
2. re.search(pattern, string[, flags])
search方法與match方法極其類似,區(qū)別在于match()函數(shù)只檢測(cè)re是不是在string的開始位置匹配,search()會(huì)掃描整個(gè)string查找匹配,match()只有在0位置匹配成功的話才有返回,如果不是開始位置匹配成功的話,match()就返回None。同樣,search方法的返回對(duì)象同樣match()返回對(duì)象的方法和屬性。
"""search方法""" import re # search查找第一次出現(xiàn) ret = re.search('www', 'www.aaa.com www.bbb.com') print(type(ret)) print(ret.group()) print(ret.span()) #匹配不成功,返回None print(re.search('cn', 'www.aaa.com www.bbb.com')) line = "Cats are smarter than dogs"; searchObj = re.search(r'(.*) are (.*?) .*', line, re.M | re.I) if searchObj: print("searchObj.group() : ", searchObj.group()) print("searchObj.group(1) : ", searchObj.group(1)) print("searchObj.group(2) : ", searchObj.group(2)) else: print("Nothing found!!")
3. re.findall(pattern, string[, flags])
搜索string,以列表形式返回全部能匹配的子串。
"""findall方法""" import re # 查找數(shù)字 result1 = re.findall(r'\d+','baidu 123 google 456') result2 = re.findall(r'\d+','baidu88oob123google456') print(result1) print(result2)
4. re.finditer(pattern, string[, flags])
搜索string,返回一個(gè)順序訪問每一個(gè)匹配結(jié)果(Match對(duì)象)的迭代器。
"""finditer方法""" import re #返回一個(gè)迭代器,可以循環(huán)訪問,每次獲取一個(gè)Match對(duì)象 it = re.finditer(r"\d+", "12a32bc43jf3") for match in it: print(match.group())
5. re.split(pattern, string[, maxsplit])
按照能夠匹配的子串將string分割后返回列表。maxsplit用于指定最大分割次數(shù),不指定將全部分割。
6. re.sub(pattern, repl, string, count=0, flags=0)
"""sub方法""" import re phone = "2004-959-559 # 這是一個(gè)國外電話號(hào)碼" # 刪除字符串中的 Python注釋 num = re.sub(r'#.*$', "", phone) print("電話號(hào)碼是: ", num) # 刪除非數(shù)字(-)的字符串 num = re.sub(r'\D', "", phone) print("電話號(hào)碼是 : ", num) # 將匹配的數(shù)字乘以 2 def double(matched): value = int(matched.group('value')) return str(value * 2) s = 'A23G4HFD567' print(re.sub('(?P<value>\d+)', double, s))
參數(shù)說明:
1 repl:用于替換的字符串 2 string:要被替換的字符串 3 count:替換的次數(shù)
7. re.subn(pattern, repl, string[, count])
與sub()函數(shù)一致,返回結(jié)果是一個(gè)元組。
8. re.compile(pattern[, flags])
該函數(shù)用于編譯正則表達(dá)式生成一個(gè)正則表達(dá)式(pattern)對(duì)象,供match()和search()等函數(shù)使用。
"""compile方法""" import re # 用于匹配至少一個(gè)數(shù)字 pattern = re.compile(r'\d+') # 查找頭部,沒有匹配 m = pattern.match('one12twothree34four') print(m) # 從'e'的位置開始匹配,沒有匹配 m = pattern.match('one12twothree34four', 2, 10) print(m) # 從'1'的位置開始匹配,正好匹配,返回一個(gè) Match 對(duì)象 m = pattern.match('one12twothree34four', 3, 10) print(m) # 可省略 0 print(m.group(0))
Beautiful Soup,有了它我們可以很方便地提取出 HTML 或 XML 標(biāo)簽中的內(nèi)容。BeautifulSoup是一個(gè)高效的網(wǎng)頁解析庫,可以從 HTML 或 XML 文件中提取數(shù)據(jù)。
beautifulsoup支持不同的解析器,比如,對(duì)HTML解析,對(duì)XML解析,對(duì)HTML5解析。一般情況下,我們用的比較多的是 lxml 解析器。
1 pip install beautifulsoup4
使用時(shí)導(dǎo)入:
1 from bs4 import BeautifulSoup
解析器 | 使用方法 | 條件 |
bs4的HTML解析器 | BeautifulSoup(html,'html.parser') | 安裝bs4庫 |
lxml的HTML解析器 | BeautifulSoup(html,'lxml') | pip install lxml |
lxml的XML解析器
|
BeautifulSoup(html,'xml') | pip install lxml |
html5lib的解析器 | BeautifulSoup(html,'htmlslib') | pip install html5lib |
"""將字符串解析為HTML文檔解析""" from bs4 import BeautifulSoup html = """ <html><head><title>The Dormouse's story</title></head> <body> <p class="title" name="dromouse"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were <a class="sister" id="link1"><!-- Elsie --></a>, <a class="sister" id="link2">Lacie</a> and <a class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <p class="story">...</p> """ # 創(chuàng)建BeautifulSoup對(duì)象解析html,并使用lxml作為xml解析器soup = BeautifulSoup(html, 'lxml') # 格式化輸出soup對(duì)象的內(nèi)容 print(soup.prettify())
例一:
"""bs4實(shí)例測(cè)試""" from bs4 import BeautifulSoup import re html = """ <html><head><title>The Dormouse's story</title></head> <body> <p class="title" name="dromouse"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were <a class="sister" id="link1"><!-- Elsie --></a>, <a class="sister" id="link2">Lacie</a> and <a class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <p class="story">...</p> """ # 創(chuàng)建對(duì)象 soup = BeautifulSoup(html, 'lxml') # 獲取Tag對(duì)象 # 查找的是在所有內(nèi)容中的第一個(gè)符合要求的標(biāo)簽 print(soup.title) print(type(soup.title)) print(soup.p) # 標(biāo)簽的名字 print(soup.p.name) # 標(biāo)簽的屬性,可獲取,也可以設(shè)置 print(soup.p.attrs) print(soup.p.attrs['class']) # 文本 print(soup.p.string) # content屬性得到子節(jié)點(diǎn),列表類型 print(soup.body.contents) # children屬性屬性得到子節(jié)點(diǎn),可迭代對(duì)象 print(soup.body.children) # descendants屬性屬性得到子孫節(jié)點(diǎn),可迭代對(duì)象 print(soup.body.descendants) # find_all 查找所有符合要求的 name是按照標(biāo)簽名字查找 print(soup.find_all(name='b')) print(soup.find_all(name=['a', 'b'])) print(soup.find_all(name=re.compile("^b"))) # find_all 查找所有符合要求的 可以按照屬性查找,比如這里的id,class # 因?yàn)閏lass是關(guān)鍵字,所以使用class_代替class print(soup.find_all(id='link2')) print(soup.find_all(class_='sister')) # select 查找所有符合要求的 支持選擇器 print(soup.select('title')) print(soup.select('.sister')) print(soup.select('#link1')) print(soup.select('p #link1')) print(soup.select('a[class="sister"]')) # 獲取內(nèi)容 print(soup.select('title')[0].get_text())
例二:
>>> from bs4 import BeautifulSoup >>> import requests >>> r = requests.get("http://python123.io/ws/demo.html") >>> demo = r.text >>> demo '<html><head><title>This is a python demo page</title></head>\r\n<body>\r\n<p class="title"><b>The demo python introduces several python courses.</b></p>\r\n<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\n<a class="py1" id="link1">Basic Python</a> and <a class="py2" id="link2">Advanced Python</a>.</p>\r\n</body></html>' >>> soup = BeautifulSoup(demo,"html.parser") >>> soup.title #獲取標(biāo)題 <title>This is a python demo page</title> >>> soup.a #獲取a標(biāo)簽 <a class="py1" id="link1">Basic Python</a> >>> soup.title.string 'This is a python demo page' >>> soup.prettify() #輸出html標(biāo)準(zhǔn)格式內(nèi)容 '<html>\n <head>\n <title>\n This is a python demo page\n </title>\n </head>\n <body>\n <p class="title">\n <b>\n The demo python introduces several python courses.\n </b>\n </p>\n <p class="course">\n Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\n <a class="py1" id="link1">\n Basic Python\n </a>\n and\n <a class="py2" id="link2">\n Advanced Python\n </a>\n .\n </p>\n </body>\n</html>' >>> soup.a.name #每個(gè)<tag>都有自己的名字,通過<tag>.name獲取 'a' >>> soup.p.name 'p' >>> tag = soup.a >>> tag.attrs {'href': 'http://www.icourse163.org/course/BIT-268001', 'class': ['py1'], 'id': 'link1'} >>> tag.attrs['class'] ['py1'] >>> tag.attrs['href'] 'http://www.icourse163.org/course/BIT-268001' >>> type(tag.attrs) <class 'dict'> >>> type(tag) <class 'bs4.element.Tag'>
xml被用來傳輸和存儲(chǔ)數(shù)據(jù)。參考:https://www.runoob.com/xml/xml-tutorial.html
參考:https://www.runoob.com/xpath/xpath-tutorial.html
xml被設(shè)計(jì)用來傳輸和存儲(chǔ)數(shù)據(jù),HTML被設(shè)計(jì)用來顯示數(shù)據(jù)。這兩個(gè)都是樹形結(jié)構(gòu),可以先將HTML文件轉(zhuǎn)換成xml文檔,然后用xpath語法查找HTML節(jié)點(diǎn)或元素。這樣就用到了lxml模塊
# lxml安裝: pip install lxml # 使用 (1) """將字符串解析為HTML文檔""" from lxml import etree text=''' <div> <ul> <liclass="item-0"><ahref="link1.html">firstitem</a></li> <liclass="item-1"><ahref="link2.html">seconditem</a></li> <liclass="item-inactive"><ahref="link3.html">thirditem</a></li> <liclass="item-1"><ahref="link4.html">fourthitem</a></li> <liclass="item-0"><ahref="link5.html">fifthitem</a> </ul> </div> ''' #利用etree.HTML,將字符串解析為HTML文檔 html=etree.HTML(text) #按字符串序列化HTML文檔 result=etree.tostring(html).decode('utf-8') print(result) (2) """讀文件""" from lxml import etree # 讀取外部文件hello.html html = etree.parse('./data/hello.html') # pretty_print=True表示格式化,比如左對(duì)齊和換行 result = etree.tostring(html, pretty_print=True).decode('utf-8') print(result)
聯(lián)系客服