一.理解網(wǎng)絡(luò)爬蟲(chóng)1.1爬蟲(chóng)的定義網(wǎng)絡(luò)爬蟲(chóng)又稱為網(wǎng)頁(yè)蜘蛛、網(wǎng)絡(luò)機(jī)器人。網(wǎng)絡(luò)爬蟲(chóng)是一種按照一定的規(guī)則自動(dòng)的抓取網(wǎng)絡(luò)信息的程序或者腳本。通俗的說(shuō),就是根據(jù)一定的算法實(shí)現(xiàn)編程開(kāi)發(fā),主要通過(guò)URL實(shí)現(xiàn)數(shù)據(jù)的抓取和挖掘。 1.2爬蟲(chóng)的類型根據(jù)系統(tǒng)結(jié)構(gòu)和開(kāi)發(fā)技術(shù)大致可分為4種類型: (1)通用網(wǎng)絡(luò)爬蟲(chóng),又稱為全網(wǎng)爬蟲(chóng),常見(jiàn)的有百度,Google等。 (2)聚焦網(wǎng)絡(luò)爬蟲(chóng),又稱主題網(wǎng)絡(luò)爬蟲(chóng),是選擇性的爬行根據(jù)需求的主題相關(guān)頁(yè)面的網(wǎng)絡(luò)爬蟲(chóng)。 (3)增量式網(wǎng)絡(luò)爬蟲(chóng)。是指對(duì)已下載網(wǎng)頁(yè)采取增量式更新和只爬行新產(chǎn)生或者已經(jīng)發(fā)生變化的網(wǎng)頁(yè)的爬蟲(chóng),它能夠在一定程度上保證所爬行的頁(yè)面盡可能是新的頁(yè)面。只會(huì)在需要的時(shí)候爬行新產(chǎn)生或發(fā)生更新的頁(yè)面,并不重新下載沒(méi)有發(fā)生變化的頁(yè)面,這類爬蟲(chóng)在實(shí)際中不太普及。 (4)深層網(wǎng)絡(luò)爬蟲(chóng)。是大部分內(nèi)容不能通過(guò)靜態(tài)URL獲取的,隱藏在表單后的,只有用戶提交一些關(guān)鍵詞才能獲得的網(wǎng)絡(luò)頁(yè)面。 這四類大致又可以分為兩類,通用爬蟲(chóng)和聚焦爬蟲(chóng)。聚焦網(wǎng)絡(luò)爬蟲(chóng),增量式網(wǎng)絡(luò)爬蟲(chóng)和深層網(wǎng)絡(luò)爬蟲(chóng)可歸為一類,因?yàn)樗麄兪嵌ㄏ蚺老x(chóng)數(shù)據(jù)。而通用爬蟲(chóng)在網(wǎng)絡(luò)上稱為搜索引擎。 爬蟲(chóng)的設(shè)計(jì)思路: (1) 明確需要爬取的網(wǎng)頁(yè)的URL地址; (2)通過(guò)http請(qǐng)求來(lái)獲取對(duì)應(yīng)的HTML頁(yè)面; (3)提取HTML的內(nèi)容。若是有用的數(shù)據(jù),就保存起來(lái);若是繼續(xù)爬取的頁(yè)面,就重新指定第(2)步。 二.爬蟲(chóng)開(kāi)發(fā)基礎(chǔ)2.1 HTTP與HTTPShttp是一個(gè)簡(jiǎn)單的請(qǐng)求-響應(yīng)協(xié)議,它通常運(yùn)行在TCP之上。它指定了客戶端可能發(fā)送給服務(wù)器什么樣的消息以及得到什么樣的響應(yīng)。客戶端是終端用戶,服務(wù)器端是網(wǎng)站。通常使用web瀏覽器,網(wǎng)絡(luò)爬蟲(chóng)或者其他工具,客戶端會(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)行一次握手,在握手過(guò)程中將確立雙方加密傳輸數(shù)據(jù)的密碼信息。 2.2 請(qǐng)求頭請(qǐng)求頭描述客戶端向服務(wù)器發(fā)送請(qǐng)求時(shí)使用的協(xié)議類型,所使用的編碼以及發(fā)送內(nèi)容的長(zhǎng)度等。檢測(cè)請(qǐng)求頭是常見(jiàn)的反爬蟲(chóng)策略。因?yàn)榉?wù)器會(huì)對(duì)請(qǐng)求頭做一次檢測(cè)來(lái)判斷此次請(qǐng)求是人為的還是非人為的。所以我們?cè)诿看伟l(fā)送請(qǐng)求時(shí)都添加上請(qǐng)求頭。 請(qǐng)求頭的參數(shù)如下: (1)Accept:瀏覽器可以接收的類型 (2)Accept-Charset:編碼類型 (3)Accept-Encoding:可以接收壓縮編碼類型 (4)Accept-Language:可以接收的語(yǔ)言和國(guó)家類型 (5)Host:請(qǐng)求的主機(jī)地址和端口 (6)Referer:請(qǐng)求來(lái)自于那個(gè)頁(yè)面的URL (7)User-Agent:瀏覽器相關(guān)信息 (8)Cookie:瀏覽器暫存服務(wù)器發(fā)送的信息 (9)Connection:http請(qǐng)求版本的特點(diǎn) (10)Date:請(qǐng)求網(wǎng)站的時(shí)間 2.3 cookies它是指某些網(wǎng)站為了辯護(hù)用戶身份,進(jìn)行session跟蹤而存儲(chǔ)在用戶本地終端上的數(shù)據(jù)。一個(gè)cookies就是存儲(chǔ)在用戶主機(jī)瀏覽器 的文本文件。 服務(wù)器可以利用cookies包含的信息判斷在http傳輸中的狀態(tài)。 2.4 JSONJSON(JavaScript Object Notation, JS 對(duì)象簡(jiǎn)譜) 是一種輕量級(jí)的數(shù)據(jù)交換格式。它基于ECMAScript (歐洲計(jì)算機(jī)協(xié)會(huì)制定的js規(guī)范)的一個(gè)子集,采用完全獨(dú)立于編程語(yǔ)言的文本格式來(lái)存儲(chǔ)和表示數(shù)據(jù)。簡(jiǎn)潔和清晰的層次結(jié)構(gòu)使得 JSON 成為理想的數(shù)據(jù)交換語(yǔ)言。 易于人閱讀和編寫,同時(shí)也易于機(jī)器解析和生成,并有效地提升網(wǎng)絡(luò)傳輸效率。 例如: {"name": "John Doe", "age": 18, "address": {"country" : "china", "zip-code": "10000"}} 2.5 JavaScriptJavaScript(簡(jiǎn)稱“JS”) 是一種具有函數(shù)優(yōu)先的輕量級(jí),解釋型或即時(shí)編譯型的高級(jí)編程語(yǔ)言。是一種解釋性腳本語(yǔ)言(代碼不進(jìn)行預(yù)編譯), 主要用來(lái)向HTML(標(biāo)準(zhǔn)通用標(biāo)記語(yǔ)言下的一個(gè)應(yīng)用)頁(yè)面添加交互行為。 JavaScript還能根據(jù)用戶觸發(fā)某些事件對(duì)用戶的操作進(jìn)行加工處理。要在爬蟲(chóng)實(shí)現(xiàn)一些功能,就要分析JS如何執(zhí)行整個(gè)用戶登錄過(guò)程。 2.6 Ajax Ajax 不是一種新的編程語(yǔ)言,而是一種用于創(chuàng)建更好更快以及交互性更強(qiáng)的Web應(yīng)用程序的技術(shù)。使用 JavaScript 向服務(wù)器提出請(qǐng)求并處理響應(yīng)而不阻塞用戶核心對(duì)象XMLHttpRequest。通過(guò)這個(gè)對(duì)象,您的 JavaScript 可在不重載頁(yè)面的情況與 Web 服務(wù)器交換數(shù)據(jù),即在不需要刷新頁(yè)面的情況下,就可以產(chǎn)生局部刷新的效果。
Ajax 在瀏覽器與 Web 服務(wù)器之間使用異步數(shù)據(jù)傳輸(HTTP 請(qǐng)求),這樣就可使網(wǎng)頁(yè)從服務(wù)器請(qǐng)求少量的信息,而不是整個(gè)頁(yè)面。
判斷網(wǎng)頁(yè)數(shù)據(jù)是否使用ajax的方法:觸發(fā)事件之后,判斷網(wǎng)頁(yè)是否發(fā)生刷新?tīng)顟B(tài)。若網(wǎng)頁(yè)沒(méi)有發(fā)生刷新,數(shù)據(jù)就自動(dòng)生成,說(shuō)明數(shù)據(jù)的加載是通過(guò)ajax生成并渲染到網(wǎng)頁(yè)上的。反之,數(shù)據(jù)是通過(guò)服務(wù)器后臺(tái)生成并加載的。
三.Fiddler抓包工具Fiddler是一個(gè)http協(xié)議調(diào)試代理工具,它能夠記錄并檢查所有你的電腦和互聯(lián)網(wǎng)之間的http通訊,設(shè)置斷點(diǎn),查看所有的“進(jìn)出”Fiddler的數(shù)據(jù)(指cookie,html,js,css等文件)。 3.1 fiddler安裝配置在官網(wǎng)網(wǎng)站下載(https://www./download/fiddler),界面如下圖所示: 配置fiddler,使其能夠抓取https請(qǐng)求信息: (1)打開(kāi)菜單-tools-fidder options-https。 (2)勾選https中的選項(xiàng),然后點(diǎn)擊actions-trust root certificate,完成整數(shù)驗(yàn)證。 3.2 fiddler抓取手機(jī)應(yīng)用fiddler可通過(guò)同一無(wú)線網(wǎng)絡(luò)實(shí)現(xiàn)對(duì)手機(jī)應(yīng)用的抓包,手機(jī)抓包主要通過(guò)遠(yuǎn)程連接實(shí)現(xiàn)手機(jī)和fiddler通信。 實(shí)現(xiàn)fiddler抓取手機(jī)應(yīng)用的步驟如下: (1)配置fiddler遠(yuǎn)程連接模式。打開(kāi)菜單欄: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)到證書(shū)下載頁(yè)面,點(diǎn)擊下載fiddlerroot certificate. (4)證書(shū)文件以cer為后綴名,完成證書(shū)安裝后,進(jìn)入手機(jī)當(dāng)前連接WiFi詳情,設(shè)置代理IP,主機(jī)名為電腦IP地址,端口為fiddler配置的端口。 四.開(kāi)始爬蟲(chóng)4.1 urllib模塊在python3中不存在urllib2模塊,同一為urllib。urllib模塊有如下四個(gè)子模塊: 1 urllib.request:用來(lái)打開(kāi)和讀取URL。 2 urllib.error:包含了urllib.request產(chǎn)生的異常。 3 urllib.parse:用來(lái)解析和處理URL。 4 urllib.robotparse:用于解析robots.txt文件。 urllib的方法及使用: 1 urllib.urlopen(url[, data[, proxies[,timeout[, context]]]]) 功能說(shuō)明:urllib是用于訪問(wèn)URL的唯一方法 功能說(shuō)明:聲明一個(gè)request對(duì)象,該對(duì)象可定義header等請(qǐng)求信息
"""urllib的使用""" # 導(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打開(kāi)req html = urllib.request.urlopen(req).read().decode('utf-8') # 寫入文件 f = open('code2.txt', 'w', encoding='utf8') f.write(html) f.close() 4.2 requests模塊requests模塊是在urllib的基礎(chǔ)上做了封裝,具備urllib的全部功能,讓使用者更加方便的使用。 安裝:pip install requests 4.2.1 發(fā)出請(qǐng)求有兩種方式: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表示訪問(wèn)成功,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:///get') # 發(fā)送get請(qǐng)求 print(r.text) # 發(fā)送post請(qǐng)求,并帶參數(shù) r = requests.get('https:///get', params={'key1': 'value1', 'key2': 'value2'}) print(r.text) # 發(fā)送post請(qǐng)求,并傳遞參數(shù) r = requests.post('https:///post', data={'key': 'value'}) print(r.text) # 其他HTTP請(qǐng)求類型:PUT,DELETE,HEAD和OPTIONS r = requests.put('https:///put', data={'key': 'value'}) print(r.text) r = requests.delete('https:///delete') print(r.text) r = requests.head('https:///get') print(r.text) r = requests.options('https:///get') print(r.text) 4.2.2 復(fù)雜的請(qǐng)求方式(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)證書(shū)驗(yàn)證 import requests url = 'https://kyfw.12306.cn/otn/leftTicket/init' # 關(guān)閉證書(shū)驗(yàn)證 r = requests.get(url, verify=False) print(r.status_code) # 開(kāi)啟證書(shū)驗(yàn)證 # r = requests.get(url, verify=True) # 設(shè)置證書(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 4.2.3 錯(cuò)誤和異常若出現(xiàn)網(wǎng)絡(luò)問(wèn)題,則請(qǐng)求將引發(fā)connectionerror異常。 若http請(qǐng)求返回不成功的狀態(tài)碼,則將會(huì)引發(fā)httperror異常。 若請(qǐng)求超時(shí),則會(huì)引起超時(shí)異常。 若請(qǐng)求超過(guò)配置的最大重定向數(shù),則會(huì)引發(fā)TooManyRedirects異常。 請(qǐng)求顯示引發(fā)的所有異常都繼承自requests.exceptions.RequestException。 4.3 re模塊正則表達(dá)式是對(duì)字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個(gè)“規(guī)則字符串”,這個(gè)“規(guī)則字符串”用來(lái)表達(dá)對(duì)字符串的一種過(guò)濾邏輯。 正則表達(dá)式是對(duì)字符串(包括普通字符(例如,a 到 z 之間的字母)和特殊字符(稱為“元字符”))操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個(gè)“規(guī)則字符串”,這個(gè)“規(guī)則字符串”用來(lái)表達(dá)對(duì)字符串的一種過(guò)濾邏輯。正則表達(dá)式是一種文本模式,該模式描述在搜索文本時(shí)要匹配的一個(gè)或多個(gè)字符串。 語(yǔ)法請(qǐng)參考:https://www.runoob.com/regexp/regexp-tutorial.html 4.3.1 模塊內(nèi)容 1. re.match(pattern, string[, flags]) 這個(gè)方法將會(huì)從string(我們要匹配的字符串)的開(kāi)頭開(kāi)始,嘗試匹配pattern,一直向后匹配,如果遇到無(wú)法匹配的字符,立即返回None,如果匹配未結(jié)束已經(jīng)到達(dá)string的末尾,也會(huì)返回None。兩個(gè)結(jié)果均表示匹配失敗,否則匹配pattern成功,同時(shí)匹配終止,不再對(duì)string向后匹配。 """match方法""" import re # match在起始位置匹配 ret = re.match('www', 'www.') print(type(ret)) # 獲取匹配的內(nèi)容 print(ret.group()) # 獲取匹配內(nèi)容在原字符串里的下標(biāo) print(ret.span()) # 匹配不成功,返回None print(re.match('com', 'www.')) 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ù)說(shuō)明: · pattern:匹配的正則表達(dá)式 · string:要匹配的字符串 · flags:標(biāo)志位,用于控制正則表達(dá)式的匹配方式,如是否區(qū)分大小寫,是否多行匹配等。 flags參數(shù)可選值: · re.I: 忽略大小寫(括號(hào)內(nèi)是完整寫法,下同) · re.M: 多行模式,改變'^'和'$'的行為(參見(jiàn)上圖) · 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的開(kāi)始位置匹配,search()會(huì)掃描整個(gè)string查找匹配,match()只有在0位置匹配成功的話才有返回,如果不是開(kāi)始位置匹配成功的話,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è)順序訪問(wèn)每一個(gè)匹配結(jié)果(Match對(duì)象)的迭代器。 """finditer方法""" import re #返回一個(gè)迭代器,可以循環(huán)訪問(wè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è)國(guó)外電話號(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ù)說(shuō)明: 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éi)有匹配 m = pattern.match('one12twothree34four') print(m) # 從'e'的位置開(kāi)始匹配,沒(méi)有匹配 m = pattern.match('one12twothree34four', 2, 10) print(m) # 從'1'的位置開(kāi)始匹配,正好匹配,返回一個(gè) Match 對(duì)象 m = pattern.match('one12twothree34four', 3, 10) print(m) # 可省略 0 print(m.group(0))
4.4BeautifulSoup4模塊4.4.1 簡(jiǎn)介Beautiful Soup,有了它我們可以很方便地提取出 HTML 或 XML 標(biāo)簽中的內(nèi)容。BeautifulSoup是一個(gè)高效的網(wǎng)頁(yè)解析庫(kù),可以從 HTML 或 XML 文件中提取數(shù)據(jù)。 beautifulsoup支持不同的解析器,比如,對(duì)HTML解析,對(duì)XML解析,對(duì)HTML5解析。一般情況下,我們用的比較多的是 lxml 解析器。 4.4.2 安裝1 pip install beautifulsoup4
使用時(shí)導(dǎo)入: 1 from bs4 import BeautifulSoup 4.4.3 BeautifulSoup庫(kù)解析器
4.4.4 使用"""將字符串解析為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 href="http:///elsie" class="sister" id="link1"><!-- Elsie --></a>, <a href="http:///lacie" class="sister" id="link2">Lacie</a> and <a href="http:///tillie" 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()) 例一: >>> from bs4 import BeautifulSoup >>> import requests >>> r = requests.get("http:///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>都有自己的名字,通過(guò)<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'> 五.更多數(shù)據(jù)提取的方式5.1 XPath和lxml5.1.1 xmlxml被用來(lái)傳輸和存儲(chǔ)數(shù)據(jù)。參考:https://www.runoob.com/xml/xml-tutorial.html 5.1.2 xpath參考:https://www.runoob.com/xpath/xpath-tutorial.html 5.1.3 lxmlxml被設(shè)計(jì)用來(lái)傳輸和存儲(chǔ)數(shù)據(jù),HTML被設(shè)計(jì)用來(lái)顯示數(shù)據(jù)。這兩個(gè)都是樹(shù)形結(jié)構(gòu),可以先將HTML文件轉(zhuǎn)換成xml文檔,然后用xpath語(yǔ)法查找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)
|
|