項目一 網(wǎng)絡數(shù)據(jù)采集_第1頁
項目一 網(wǎng)絡數(shù)據(jù)采集_第2頁
項目一 網(wǎng)絡數(shù)據(jù)采集_第3頁
項目一 網(wǎng)絡數(shù)據(jù)采集_第4頁
項目一 網(wǎng)絡數(shù)據(jù)采集_第5頁
已閱讀5頁,還剩95頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

項目一網(wǎng)絡數(shù)據(jù)采集

主講人:熊

勇網(wǎng)絡數(shù)據(jù)采集利器:網(wǎng)絡爬蟲學習目標知識目標:(1)了解爬蟲的概念和基本原理;(2)掌握在Python中實現(xiàn)爬蟲請求的兩個庫urllib和requests;(3)掌握常見的數(shù)據(jù)解析的方法(正則表達式、BeautifulSoup、XPath、pyquery);(4)掌握爬取動態(tài)渲染網(wǎng)頁數(shù)據(jù)的知識(通過Selenium驅動瀏覽器獲取網(wǎng)頁源碼);(5)掌握基于Scrapy框架開發(fā)爬蟲的知識。技能目標:(1)能敘述爬蟲的原理、具有通過urllib或requests庫實現(xiàn)請求并獲得HTML源碼的能力;(2)能利用正則表達式、BeautifulSoup、XPath、pyquery進行網(wǎng)頁數(shù)據(jù)的解析和提??;(3)具有基于Selenium開發(fā)爬蟲程序爬取動態(tài)渲染網(wǎng)頁數(shù)據(jù)的能力;(4)能開發(fā)基于Scrapy的爬蟲應用程序。任務1認識網(wǎng)絡爬蟲任務2數(shù)據(jù)解析任務3采集動態(tài)渲染網(wǎng)頁的數(shù)據(jù)任務4使用Scrapy框架網(wǎng)絡數(shù)據(jù)采集利器:網(wǎng)絡爬蟲CONTENTS任務導航本模塊知識框架:在本次任務中,我們將完成一個爬蟲程序,用來向數(shù)字中國站點發(fā)送請求以獲得其首頁的HTML源碼,最后將源碼保存到TXT文件中。下面讓我們一起開始學習吧。一、了解網(wǎng)絡爬蟲(一)什么是網(wǎng)絡爬蟲網(wǎng)絡爬蟲(又稱網(wǎng)頁蜘蛛或網(wǎng)絡機器人)是一種按照一定的規(guī)則,自動地抓取互聯(lián)網(wǎng)上的信息的程序或腳本。一、了解網(wǎng)絡爬蟲(二)網(wǎng)絡爬蟲的應用搜索引擎爬蟲大數(shù)據(jù)信息采集金融數(shù)據(jù)采集網(wǎng)絡輿情檢測客戶數(shù)據(jù)收集一、了解網(wǎng)絡爬蟲(三)網(wǎng)絡爬蟲的基本流程(1)首先選取一部分精心挑選的種子URL。(2)將這些URL放入待抓取URL隊列。(3)從待抓取URL隊列中取出待抓取URL,解析得到主機的網(wǎng)絡協(xié)議地址,并將URL對應的網(wǎng)頁下載下來,存儲進已下載的網(wǎng)頁庫中。然后,將這些URL放進已抓取URL隊列。(4)分析已抓取URL隊列中的URL,分析其中的其他URL,并且將URL放入待抓取URL隊列,從而進入下一個循環(huán)。一、了解網(wǎng)絡爬蟲(四)Http請求與響應在我們輸入網(wǎng)址,按下回車這個過程中,到底發(fā)生了什么呢?其中最重要的一個過程就是HTTP請求與響應,我們可以將瀏覽器看作客戶端(Client);對應網(wǎng)站的服務器就是Server;它們通過直接發(fā)送HTTP消息來通信。一、了解網(wǎng)絡爬蟲(五)Http消息HTTP請求消息的一般格式HTTP響應消息的一般格式二、實現(xiàn)爬蟲請求(一)用urllib實現(xiàn)請求urllib提供了一個基礎函數(shù)urlopen,通過向指定URL字符串的站點發(fā)出請求來獲取數(shù)據(jù)。使用前需要先導入urllib中的request模塊?!景咐?-1-1】實現(xiàn)一個完整的請求與響應模型,示例代碼如下所示。importurllib.requestres=urllib.request.urlopen('')print(res.read().decode('utf-8'))二、實現(xiàn)爬蟲請求(二)用requests實現(xiàn)請求requests是基于urllib實現(xiàn)的,使用更方便;可以通過pipinstallrequests安裝;【案例1-1-8】以GET請求作為示例實現(xiàn)一個完整的請求與響應模型,示例代碼如下所示。importrequestsr=requests.get('/')print(r.content)通過對比可以看出,requests比urllib實現(xiàn)方式簡潔許多。二、實現(xiàn)爬蟲請求(二)用requests實現(xiàn)請求【案例1-1-9】實現(xiàn)一個完整的POST請求與響應模型,示例代碼如下所示。importrequestspostdata={'key':'value'}r=requests.post('/post',data=postdata)print(r.content)可以看出,requests.post()方法傳遞了一個data參數(shù)。將需要向服務器發(fā)送的數(shù)據(jù)以字典的形式封裝,然后用POST請求的data參數(shù)發(fā)送。二、實現(xiàn)爬蟲請求(三)構造請求頭有些站點需要在請求中添加請求頭才能獲得響應數(shù)據(jù)。請求頭的信息可以在瀏覽器的開發(fā)者面板中復制。下圖是在Chrome瀏覽器中打開“”站點,然后在開發(fā)者面板的“網(wǎng)絡”卡片中瀏覽請求頭信息的效果。

選擇名稱列的第一個請求文件“”

在右邊“標頭”中查看“Cookie”和“User-Agent”等標頭信息。復制需要的標頭信息用于構造請求頭。任務實踐1任務要求:獲得“數(shù)字中國”首頁的HTML源碼并將源碼保存到文件中去。請分別使用urllib庫和requests庫來實現(xiàn)。1.

使用urllib實現(xiàn)importurllib.requestheaders={"User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/Safari/537.36","Cookie":"Secure;insert_cookie=77731460"}url='/'request=urllib.request.Request(url=url,headers=headers)#構造請求對象response=urllib.request.urlopen(request)

#發(fā)送請求獲得響應html=response.read().decode('utf-8')

#解碼獲得源碼print(html)withopen('szzg_index1.txt','w',encoding='utf-8')asfile:

#寫入文本文件file.write(html)任務實踐1任務要求:獲得“數(shù)字中國”首頁的HTML源碼并將源碼保存到文件中去。請分別使用urllib庫和requests庫來實現(xiàn)。2.

使用requests實現(xiàn)importrequestsheaders={"User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/Safari/537.36","Cookie":"Secure;insert_cookie=77731460"}url='/'response=requests.get(url=url,headers=headers)#GET請求獲得響應response.encoding='utf-8'

#設置響應的編碼為utf-8html=response.text

#解碼獲得源碼print(html)withopen('szzg_index2.txt','w',encoding='utf-8')asfile:

#寫入文本文件file.write(html)任務1認識網(wǎng)絡爬蟲任務2數(shù)據(jù)解析任務3采集動態(tài)渲染網(wǎng)頁的數(shù)據(jù)任務4使用Scrapy框架網(wǎng)絡數(shù)據(jù)采集利器:網(wǎng)絡爬蟲CONTENTS任務2-案例導入以網(wǎng)站(/)為例,我們來學習如何從其網(wǎng)頁HTML源碼中解析出引言數(shù)據(jù)。任務2-任務導航一、使用正則表達式解析(一)正則語法部分正則表達式模式描述模式描述.匹配任意字符(不包括換行符)\A匹配字符串開始位置,忽略多行模式^匹配開始位置,多行模式下匹配每一行的開始\Z匹配字符串結束位置,忽略多行模式$匹配結束位置,多行模式下匹配每一行的結束\b匹配位于單詞開始或結束位置的空字符串*匹配前一個元字符0到多次\B匹配不在單詞開始或結束位置的空字符串+匹配前一個元字符1到多次\d匹配一個數(shù)字,相當于[0-9]?匹配前一個元字符0到1次\D匹配非數(shù)字,相當于[^0-9]{m,n}匹配前一個元字符m到n次{n}精確匹配前面n個前面的表達式,如\d{5}表示匹配5個數(shù)字\w匹配字母、數(shù)字、下劃線,等價于[a-zA-Z0-9_]\w可以匹配漢字(python)\W匹配不是字母、數(shù)字、下劃線的其他字符\n()匹配括號里的表達式,也可以表示一個組\s匹配任意空白字符,相當于[\t\n\r\f\v]一、使用正則表達式解析(二)Python與正則表達式1.re.match()嘗試從字符串的起始位置匹配一個模式,如果不是起始位置匹配成功的話,就返回none,該函數(shù)的語法如下所示。re.match(pattern,string,flags=0)表1-2-2re.match()參數(shù)表參數(shù)描述pattern匹配的正則表達式string要匹配的字符串flags標志位,用于控制正則表達式的匹配方式,如是否區(qū)分大小寫、多行匹配等。參見:正則表達式修飾符-可選標志一、使用正則表達式解析(二)Python與正則表達式1.re.match()提取目標正則表達式,注意其中用()包含的兩處提取目標:(\d{7})和\d+應用正則表達式用group(1)提取第一個目標字符串;用group(2)提取第二個字符串,以此類推……group()得到的是整個正則表達式匹配到的字符串一、使用正則表達式解析(二)Python與正則表達式2.re.search()用于掃描整個字符串,并返回第一個成功的匹配,該函數(shù)的語法如下所示,該函數(shù)的語法如下所示。re.search(pattern,string,flags=0)表1-2-2re.search()參數(shù)表參數(shù)描述pattern匹配的正則表達式string要匹配的字符串flags標志位,用于控制正則表達式的匹配方式,如是否區(qū)分大小寫、多行匹配等。參見:正則表達式修飾符-可選標志該函數(shù)的參數(shù)與match函數(shù)基本一樣,但是兩個函數(shù)的區(qū)別比較明顯,match只能從開頭開始匹配,而search函數(shù)沒有這個限制,使用更靈活。一、使用正則表達式解析(二)Python與正則表達式2.re.search()案例search函數(shù)的查找目標提取目標:jwb.html和教務部注意在正則表達式中用()包含的兩處.*?最后從查找結果中提取目標字符串依然用group(1)、group(2)獲得。注意search函數(shù)只會返回第一個符合要求的目標,所以財務部不是返回結果。一、使用正則表達式解析(二)Python與正則表達式3.re.findall()返回所有匹配正則表達式的字符串。它的用法參數(shù)跟re.search()一樣,但是re.findall()方法可以匹配所有符合正則模式的字符串,每次匹配到的目標構成元組,所有的元組再構成列表對象。一、使用正則表達式解析(二)Python與正則表達式3.re.findall()案例正則表達式寫法與search函數(shù)案例一樣從這個結果可以看出,findall()函數(shù)將所有<a></a>標簽中的部門和網(wǎng)址都獲取到了,結果是一個列表;每一項的結果組成一個元組。二、使用BeautifulSoup解析(一)安裝BeautifulSoup以Windows安裝為例,在命令窗口中使用以下命令安裝:pipinstallbeautifulsoup4pipinstalllxml二、使用BeautifulSoup解析(二)基本用法(案例1-2-2)frombs4importBeautifulSoup#從bs4中引入BeautifulSoup模塊soup=BeautifulSoup(html,'lxml')#初始化對象,用lxml解析器lis=soup.ul.li

#搜索ul下的li(實際上是第一個li)print(type(lis)) #打印節(jié)點對象類型print(lis) #打印節(jié)點自身print(lis.text)

#打印li節(jié)點的文本輸出結果如下:<class'bs4.element.Tag'><liclass="xz"><ahref="jwb.html">教務部</a></li>教務部二、使用BeautifulSoup解析(三)節(jié)點選擇器1.嵌套選擇在案例1-2-2中,先通過soup.ul選擇了ul節(jié)點,然后繼續(xù)選擇了ul下的li節(jié)點,即soup.ul.li,這就是嵌套選擇。在BeautifulSoup中選擇節(jié)點返回的對象類型是bs4.element.Tag類型,這種對象還可以繼續(xù)通過節(jié)點選擇器選擇其子節(jié)點。2.子節(jié)點和子孫節(jié)點如果需要獲得某個節(jié)點的子節(jié)點或子孫節(jié)點,可以通過children和descendants屬性。如:soup.ul.children或soup.ul.descendants二、使用BeautifulSoup解析(三)節(jié)點選擇器3.父節(jié)點和祖先節(jié)點可以通過parent獲得節(jié)點的父節(jié)點;通過parents獲得節(jié)點的祖先節(jié)點。用法與childrent和descendants差不多。4.兄弟節(jié)點要取得某個節(jié)點的兄弟,有next_sibling、next_siblings、previous_sibling、previous_siblings四個屬性:next_sibling:

表示下一個兄弟節(jié)點;next_siblings:

表示后面的所有同級節(jié)點;previous_sibling:

表示前面的一個同級節(jié)點;previous_siblings:

表示前面的所有同級節(jié)點。二、使用BeautifulSoup解析(四)提取節(jié)點信息1.string和text屬性可以通過節(jié)點的string和text屬性獲得節(jié)點及其子孫節(jié)點的非屬性文本。這兩個屬性用法差不多,稍有區(qū)別:當某個節(jié)點的標簽沒有封閉的時候,用string屬性不能獲得到結果,但是text屬性可以,但是text獲取的結果最后有一個換行符,需要注意一下。2.get_text()方法通過get_test()方法可獲得未封閉標簽(節(jié)點)內的文本,不含最后的換行符??蓞⒁姲咐?-2-5。二、使用BeautifulSoup解析(五)方法選擇器1.find()方法find()方法查找的結果是符合要求的第一個節(jié)點。語法為:find(name,attrs,recursive,text,**kwargs)各參數(shù)如下:參數(shù)描述name標簽名或標簽列表,可以是字符串或正則表達式attrs標簽屬性或屬性字典,可以是字符串或字典recursive布爾值,是否對子孫節(jié)點進行遞歸搜索,默認為Truetext字符串或正則表達式,用于查找指定文本**kwargs其他屬性參數(shù),如class_二、使用BeautifulSoup解析(五)方法選擇器2.findall()方法find_all()方法顧名思義查找的是符合要求的多個節(jié)點,結果為多個節(jié)點構成的列表。除了這點結果的形式不同之外,它們的用法是非常類似的。語法為:findall(name,attrs,recursive,text,**kwargs)find()和findall()方法的具體案例請參見1-2-6。二、使用BeautifulSoup解析(六)CSS選擇器在網(wǎng)頁的HTML文檔中,很多節(jié)點標簽都具有一些類似id、class、name等等屬性,大家如果對網(wǎng)頁制作中的CSS(層疊表樣式)稍有了解,就知道在css里面經(jīng)常用節(jié)點的上面一些屬性來定位節(jié)點標簽。BeautifulSoup的Tag對象的CSS選擇器也是利用同樣的原理來定位節(jié)點的。在BeautifulSoup中使用CSS選擇器時,需要調用Tag對象的select()方法,傳入CSS定位字符串即可。該方法返回的結果類型為列表,其中元素就是要選擇的節(jié)點。關于CSS定位器的用法請參見表1-2-4。用法說明select("li")表示通過節(jié)點標簽名選擇。如:select("a"),select("ul")select("#finance")表示通過節(jié)點的id屬性查找。還可以結合節(jié)點名和id屬性一起用,如:select("li#finance")select(".xz")表示通過節(jié)點的class屬性查找,如節(jié)點class有多個值,可以用多個.引導,如:select("li.jx.dept")select("li.xz:nth-child(1)")表示查找第一個符合:前面CSS選擇器的節(jié)點,注意“:”與后面的“:nth-child(1)”中間不能有空格。select("li.xz:nth-child(2)")表示查找第二個符合:前面CSS選擇器的節(jié)點select("li:nth-child(2n)")select("li:nth-child(2n+1)")表示查找第偶數(shù)個符合前面CSS選擇器的節(jié)點。如要查找第奇數(shù)個,只需改為:select("li:nth-child(2n+1)")select("li:first-child")select("li:last-child")分別表示符合:前面CSS選擇器的第一個、最后一個節(jié)點。select("ulli.jx")表示依據(jù)上次層級來定位節(jié)點,在不同層級之間用空格或者>隔開,如:select("ul>li.jx")和select("ulli.jx")效果是一樣的。二、使用BeautifulSoup解析(六)CSS選擇器關于CSS選擇器select()的具體案例請參見1-2-7。表1-2-4CSS定位器及偽類選擇器三、使用XPath解析(一)安裝lxml包在windows命名窗口中執(zhí)行安裝命令:pipinstalllxml(二)Xpath的基本使用1.Xpath對象的初始化(用字符串初始化)fromlxmlimportetreehtml='''<divid="institution">……'''xp=etree.HTML(html)#調用HTML類初始化構造一個XPath對象print(xp.xpath('//ul//a/text()'))#獲取文檔中所有ul節(jié)點下的所有a節(jié)點的文本輸出如下:['教務部','財務部','服裝工程學院','公共課部','后勤部']三、使用XPath解析(二)Xpath的基本使用1.Xpath對象的初始化(用文件初始化)fromlxmlimportetreeparser=etree.HTMLParser(encoding='utf-8')#定義解析器使用utf-8編碼,以免中文亂碼htmlElement=etree.parse('./institution.html',parser=parser)#初始化XPath解析對象text=etree.tostring(htmlElement,encoding='utf-8')#獲得bytes字符串,指定了utf-8編碼print(htmlElement.xpath('//li[1]/a/text()'))#查找第一個li節(jié)點下的a節(jié)點,獲取文本請參見案例1-2-8。

三、使用XPath解析(二)Xpath的基本使用2.Xpath中節(jié)點的選取XPath使用路徑表達式在類XML文檔中選取節(jié)點,節(jié)點是沿著路徑來選取的。XPath路徑規(guī)則如表1-2-1所示。請參見案例1-2-8。

表1-2-1XPath路徑規(guī)則表表達式描述nodename選取此節(jié)點的所有子節(jié)點/從當前節(jié)點的直接子節(jié)點中選取,如在路徑表達式最前面表示從文檔的根節(jié)點開始//從當前節(jié)點的子孫節(jié)點中選取.選取當前節(jié)點..選取當前節(jié)點的父節(jié)點@選取屬性路徑表達式結果bookstore選取bookstore元素的所有子節(jié)點/bookstore選取根元素bookstore。注釋:假如路徑起始于正斜杠(/),則此路徑始終代表某元素的絕對路徑bookstore/book選取屬于bookstore的子元素的所有book元素//book選取所有book子元素,而不管它們在文檔中的位置bookstore//book選擇屬于bookstore元素后代的所有book元素,而不管它們位于bookstore之下的什么位置//@lang選取名為lang的所有屬性三、使用XPath解析(二)Xpath的基本使用2.Xpath中節(jié)點的選取XPath路徑規(guī)則表達式的案例如表1-2-2所示。

表1-2-2路徑表達式及其結果表三、使用XPath解析(二)Xpath的基本使用2.Xpath中節(jié)點的選取在XPath節(jié)點選取中除了使用表1-2-1的路徑規(guī)則外,往往還需要用到節(jié)點關系來定位節(jié)點,比如父節(jié)點、子節(jié)點;另外還可以對同級節(jié)點按序選擇,以及在選擇節(jié)點時通過屬性來匹配節(jié)點等等。父節(jié)點子節(jié)點按序選擇屬性匹配

三、使用XPath解析(二)Xpath的基本使用3.Xpath中節(jié)點文本的提取在XPath如果要提取某個節(jié)點的非屬性文本,可以在XPath規(guī)則表達式后面添加/text()。獲得的結果是一個列表,如需要文本本身,需要用[0]提取列表中元素。例如:print(xp.xpath('//li[contains(@class,"jx")andcontains(@class,"dept")]/a/text()')[0])輸出結果為:服裝工程學院。

三、使用XPath解析(二)Xpath的基本使用4.Xpath中節(jié)點屬性的提取得到某個節(jié)點后,經(jīng)常需要獲取其某個屬性的值,可以通過在路徑表達式后面增加/@屬性名來獲得屬性值。具體用法請參見案例1-2-17。

四、使用pyquery解析(一)pyquery的安裝1.安裝pyquery在windows命令窗口中運行以下命令:pipinstallpyquery2.pyquery對象的初始化pyquery初始化可以用hmtl字符串初始化,或者用html文件初始化,還可以用url初始化。使用起來非常自由。具體案例請見案例1-2-18/1-2-19/1-2-20。四、使用pyquery解析(二)pyquery的節(jié)點選擇1.pyquery中CSS選擇器的使用在pyquery中使用CSS選擇器與BeautifulSoup中幾乎一樣,可以參考“表1-2-4CSS定位器及偽類選擇器”中的用法。案例1-2-21演示了CSS選擇器的用法。四、使用pyquery解析(二)pyquery的節(jié)點選擇2.pyquery中方法選擇器pyquery還提供了一些方法用來查找節(jié)點。這些查找方法有find()、children()、parent()、siblings()。分別是在子孫節(jié)點中查找、只在子節(jié)點中查找子節(jié)點、查找父節(jié)點和查找兄弟節(jié)點。具體案例請見案例1-2-22~1-2-25。四、使用pyquery解析(二)pyquery的節(jié)點選擇3.pyquery中偽類選擇器所謂偽類選擇器就是當我們在PyQuery的CSS選擇器中寫出了查找節(jié)點的CSS選擇器字符串時,在字符串尾部用“:”分隔,然后跟上一些特殊的限定字符串,用來表示同類節(jié)點中的第一個、最后一個、第n個、第奇(偶)數(shù)個、包含指定文本的節(jié)點等等。具體可以參考表1-2-4。具體案例請見案例1-2-26。四、使用pyquery解析(三)pyquery中多個節(jié)點的遍歷如果查找到的結果中包含多個節(jié)點,我們又需要依次操作其中每個節(jié)點,那么就需要遍歷。遍歷需要用到items()方法。該方法返回一個生成器generator,可以用for循環(huán)遍歷一次(注意:生成器只能遍歷一次)。例如:frompyqueryimportPyQueryaspqdoc=pq(html)cwb=doc.find('li#finance')siblings_li=cwb.siblings()print(siblings_li)forliinsiblings_li.items():print(li.text())四、使用pyquery解析(四)pyquery中節(jié)點信息的獲取1.獲取節(jié)點的文本內容在pyquery中要獲取節(jié)點的非屬性文本用text()方法。例如:假設已經(jīng)查找到了節(jié)點li,為了獲取文字“服裝工程學院”,可以用li.text()得到。這里有一個細節(jié)大家要注意一下:在pyquery中用text()方法獲得的文本中包含了節(jié)點子孫節(jié)點的非屬性文本內容,這是text()的重要特點。這就是非屬性文本四、使用pyquery解析(四)pyquery中節(jié)點信息的獲取2.獲取節(jié)點的屬性有時候我們需要的數(shù)據(jù)是在某個節(jié)點的屬性里面的,就需要獲取其屬性。要獲取節(jié)點某個屬性用attr('屬性名')來實現(xiàn)。例如:frompyqueryimportPyQueryaspqhtml='<liclass="jxdept"><ahref="fzxy.html"><spanclass="bold">紡織學院</span></a></li>'doc=pq(html)a=doc('a')print(a.attr('href'))這就是屬性文本,即href屬性的內容這兩個是class屬性的文本四、使用pyquery解析(五)pyquery中節(jié)點的動態(tài)操作在pyquery中提供了對節(jié)點的動態(tài)操作,例如為節(jié)點添加或移除class屬性的方法addClass()/removeClass()、從節(jié)點中移除子孫節(jié)點的方法remove()等等。這些方法有時對數(shù)據(jù)解析可以起到很好的作用。具體用法請參考案例1-2-28。任務2-任務實踐(1)進入網(wǎng)站(/)首頁,打開開發(fā)者面板,如圖1-2-4所示??梢钥吹?,每頁10條引言對應源碼中的10個class屬性為“quote”的div元素。任務2-任務實踐(2)在下圖左邊可以看到名人引言信息,單擊選擇檢查工具(圖中標①處),或按Ctrl+Shift+C組合鍵,然后單擊第一條引言的文字內容(圖中標②處),在右邊“元素”卡片窗口會定位到該條引言內容對應的源碼。如圖1-2-5中箭頭所指處。引言內容是在一個span(class屬性為‘text’)元素中任務2-任務實踐(3)確定引言“作者”對應“元素”卡片中的位置。引言作者是在一個small標簽(class屬性為‘a(chǎn)uthor’)中任務2-任務實踐(4)確定引言“分類Tags”對應“元素”卡片中的位置。分類Tags是在一個class屬性為‘tags’的div標簽中,里面有幾個Tag就有幾個a標簽。任務2-任務實踐(5)確定頁面底部的翻頁按鈕“Next”對應“元素”卡片中的位置。翻頁“Next”按鈕對應的源碼,可知從第二頁的URL是在首頁基礎上增加”/page/i/。2<=i<=10任務2-任務實踐(6)程序實現(xiàn):①定義get_one_page函數(shù)。根據(jù)指定的URL請求網(wǎng)頁的HTML源碼,返回值為源碼字符串。#獲取指定URL頁面的源碼函數(shù),返回源碼,輸入?yún)?shù)為URL和請求頭importrequestsdefget_one_page(url,headers):try:response=requests.get(url=url,headers=headers)ifresponse.status_code==200:returnresponse.textelse:returnNoneexceptExceptionase:print(f'出錯了,錯誤信息為:{e}')returnNone任務2-任務實踐(6)程序實現(xiàn):②

定義parse_one_page函數(shù)。用于從html源碼中解析出需要的數(shù)據(jù)。frombs4importBeautifulSoupdefparse_one_page(html):soup=BeautifulSoup(html,'lxml')

#BeautifulSoup的初始化quotes=soup.find_all(class_='quote')

#查找class屬性為quote的節(jié)點,即引言所在的divforquoteinquotes:text=quote.find(class_="text").string

#用find方法查找引言內容所在節(jié)點,獲取文字author=quote.select("small.author")[0].string

#用select方法查找引言作者所在節(jié)點smalltags=quote.select("div.tags>a.tag")

#用select方法查找分類標簽所在的a節(jié)點(多個)tags_string=[]

#定義空列表,用來保存多個分類Tagforaintags:tags_string.append(a.string.strip())

#循環(huán)訪問分類標簽,并添加到列表中

yield{'text':text,

'author':author,

'tags':tags_string}#將函數(shù)變?yōu)橐粋€由字典類型數(shù)據(jù)構成的generator任務2-任務實踐(6)程序實現(xiàn):③定義一個用于將數(shù)據(jù)寫入CSV文件的函數(shù)save_to_csv(quotes)。importcsv

#引入csv模塊,提供了操作csv文件的方法defsave_to_csv(quotes):withopen('quotes.csv','w',newline="",encoding='utf-8-sig')ascsvfile:#寫入方式打開fieldnames=['text','author','tags']

#表頭標題writer=csv.DictWriter(csvfile,fieldnames=fieldnames)

#獲得寫入字典數(shù)據(jù)的writer對象writer.writeheader()

#寫入標題行forqinquotes:

#遍歷分類Tagswriter.writerow(q)

#寫入每條引言數(shù)據(jù)任務2-任務實踐(6)程序實現(xiàn):④定義main()函數(shù)。defmain():url='/'headers={

}list_quotes=[]#定義一個空列表對象,保存10頁的引言數(shù)據(jù)foriinrange(1,11):#用循環(huán)處理總共10頁的爬取,循環(huán)變量從1到10

#省略部分代碼

html=get_one_page(url=current_url,headers=headers)

#調用get_one_page獲得當前頁面的源碼forqinparse_one_page(html):

#調用parse_one_page得到一個可遍歷的generatorlist_quotes.append(q)

#將一條引言的字典對象添加到列表中save_to_csv(list_quotes)

#通過調用save_to_csv(gener_quotes)將結果寫入csv文件寫入每條引言數(shù)據(jù)從第二頁開始URL為:第一頁URL+“page/2/”,第三頁為:第一頁URL+“page/2/”,依次類推,第十頁為:第一頁URL+“page/10/”。所以可以很簡單地用foriinrange(1,11)的循環(huán),讓i從1到10,除了i=1時用基本URL,其它頁面只需要在第一頁URL后面拼接“page/i/”就可以了。任務2-任務實踐(6)程序實現(xiàn):⑤調用main()。if__name__=='__main__':main()

任務2-任務實踐(7)運行程序得到部分輸出如下:當前正在處理的頁面URL=/{'text':'“Theworldaswehavecreateditisaprocessofourthinking.Itcannotbechangedwithoutchangingourthinking.”','author':'AlbertEinstein','tags':['change','deep-thoughts','thinking','world']}{'text':'“Itisourchoices,Harry,thatshowwhatwetrulyare,farmorethanourabilities.”','author':'J.K.Rowling','tags':['abilities','choices']}{'text':'“Thereareonlytwowaystoliveyourlife.Oneisasthoughnothingisamiracle.Theotherisasthougheverythingisamiracle.”','author':'AlbertEinstein','tags':['inspirational','life','live','miracle','miracles']} 當前正在處理的頁面URL=/page/2/當前正在處理的頁面URL=/page/10/

任務1認識網(wǎng)絡爬蟲任務2數(shù)據(jù)解析任務3采集動態(tài)渲染網(wǎng)頁的數(shù)據(jù)任務4使用Scrapy框架網(wǎng)絡數(shù)據(jù)采集利器:網(wǎng)絡爬蟲CONTENTS任務3-案例導入下圖是某電商網(wǎng)站“手機”欄目商品的數(shù)據(jù),假設本次學習任務是將圖中用帶圈的6個數(shù)字標記的手機的6項信息解析出來,一共爬取前面5頁的商品數(shù)據(jù)并整理成Python字典格式,最后存入文本文件phone.txt中。圖中這6項信息按數(shù)字從小到大的順序分別是:商品名、商品圖片、商品價格、評論數(shù)、店鋪名、是否自營。任務3-任務導航一、準備Selenium的環(huán)境(一)安裝Selenium在windows命令窗口中執(zhí)行安裝命令:pipinstall-i/pypi/simple/selenium一、準備Selenium的環(huán)境(二)安裝Chrome的驅動ChromeDriver1.Chrome的不同版本對應不同版本的ChromeDriver,確定好Chrome版本后去Google官網(wǎng)(/index.html)下載對應的ChromeDriver。2.將下載的文件解壓后,找到解壓的文件中的chromedriver.exe,將其放到Path環(huán)境變量中的任一目錄。例如:“C:\Windows\System32”二、Selenium聲明瀏覽器對象(二)安裝Chrome的驅動ChromeDriver1.默認參數(shù)初始化fromseleniumimportwebdriveraswbdbrowser=wbd.Chrome()2.使用制定參數(shù)初始化chrome_options=wbd.ChromeOptions()#創(chuàng)建ChromeOptions實例,用來設定瀏覽器參數(shù)。#設置瀏覽器在屏幕上的初始位置x,y坐標,窗口的寬高值chrome_options.add_argument(f'--window-position={5},{5}')chrome_options.add_argument(f'--window-size={1000},{800}')chrome_options.add_argument('lang=zh_CN.UTF-8')#設置中文browser=wbd.Chrome(options=chrome_options)#聲明瀏覽器對象時使用參數(shù)三、Selenium獲取頁面HTML源碼通過初始化的瀏覽器對象的get()方法訪問指定URL,然后通過page_source屬性可獲取頁面的HTML源碼。例如:fromseleniumimportwebdriveraswbdbrowser=wbd.Chrome()browser.get('/')print(browser.page_source)browser.close()四、Selenium中查找網(wǎng)頁元素在程序中對文本框、按鈕、鏈接等元素進行操作前,先要將其從網(wǎng)頁中查找出來才便于在程序中完成互動操作。查找元素主要用到瀏覽器對象的find_element()方法。方法有兩個參數(shù)。第一個參數(shù)常用的有以下三種之一:By.ID、By.CSS_SELECTOR、By.XPATH等,該參數(shù)表示查找元素的方式,與前面解析網(wǎng)頁時的知識是一樣的(還有很多其它方式,請自行上網(wǎng)搜索);方法的第二個參數(shù)就是對應于所選查找方式(即第一個參數(shù))的屬性值。具體用法請參考案例1-3-1。五、操作網(wǎng)頁元素對于文本框的操作來說,主要是文字的清除、發(fā)送文字、發(fā)送回車鍵。清除文字:通過調用clear()方法可清除文本框文字;發(fā)送文字:通過send_keys()方法可以向文本框發(fā)送字符;發(fā)送回車鍵:通過send_keys(keys.ENTER)可以發(fā)送回車鍵。起到代替單擊按鈕的作用。(注:需引入frommon.keysimportKey)(一)文本框的操作具體用法請參考案例1-3-1。五、操作網(wǎng)頁元素這兩類元素的操作主要是單擊操作,在用find_element()方法查找到之后,調用元素的click()方法就可以達到單擊的效果。(二)按鈕和超鏈接的操作具體用法請參考案例1-3-1。五、操作網(wǎng)頁元素fromseleniumimportwebdriveraswbdfrommon.byimportBybrowser=wbd.Chrome()browser.get('/')key=browser.find_element(By.ID,'key') #查找id為“key”的元素button=browser.find_element(By.CSS_SELECTOR,'#search>div>div.form>button>i')#查找按鈕key.clear() #清空文本框key.send_keys('手機') #向文本框中輸入文字“手機”button.click()案例1-3-1清空文本框發(fā)送文字到文本框單擊按鈕查找文本框查找按鈕在本案例中,實現(xiàn)用selenium控制打開瀏覽器訪問某電商網(wǎng)站,在文本框中輸入“手機”關鍵字,然后搜索的操作過程。五、操作網(wǎng)頁元素在使用Selenium模擬瀏覽器時也可能需要控制頁面的垂直滾動條向下滾動,以顯示更多內容。SeleniumAPI并沒有像前面的文本框和按鈕等元素一樣提供直接的方法??梢酝ㄟ^瀏覽器對象的execute_script()方法執(zhí)行特定的JavaScript代碼來實現(xiàn)滾動條的滾動效果。(三)控制網(wǎng)頁滾動條的滾動具體用法請參考案例1-3-2。案例1-3-2是在案例1-3-1的基礎上增加下面一行代碼實現(xiàn)的: browser.execute_script('window.scrollTo(0,document.body.scrollHeight)')其中,'window.scrollTo(0,document.body.scrollHeight)'是將頁面滾動條滑動到頁面底端。提醒:執(zhí)行之后,頁面垂直滾動條并沒有停在最下面,你知道是為什么嗎?難道該程序有問題嗎?六、Selenium中獲取元素的屬性經(jīng)常要獲取某元素的屬性、非屬性文本、獲取元素本身的HTML或內部的HTML源碼。(1)get_attribute("屬性名")獲取屬性值,例如li.get_attribute("id");(2)訪問元素的text屬性獲取非屬性文本內容,例如li.text;(3)get_attribute("outerHTML")獲取元素本身的HTML源碼;(4)get_attribute("innerHTML")獲取元素內部子孫元素的HTML源碼。具體用法請參考案例1-3-3。【案例1-3-3】在案例1-3-1的基礎上,獲取第一個商品的名稱、價格。七、Selenium中延時等待網(wǎng)頁加載需要一定時間,如果一開始就用page_source屬性獲取頁面的HTML源碼,很可能因為頁面還未加載完成而得不到想要的數(shù)據(jù)。故而,在Selenium中設置了延時等待機制,設定一個等待條件,當條件達成后結束等待。部分等待條件如表1-3-1。表1-3-1Selenium中延時等待條件序號等待條件說明1title_is標題是某內容2title_contains標題含有某文字3presence_of_element_located節(jié)點加載出來,傳入元組類型數(shù)據(jù),如(By.ID,"q")4visibility_of_element_located節(jié)點可見,傳入元組類型數(shù)據(jù)5presence_of_all_elements_located所有節(jié)點加載出來,傳入元組類型數(shù)據(jù)6text_to_be_present_in_element節(jié)點文本包含某文字7element_to_be_clickable節(jié)點可以單擊8staleness_of節(jié)點是否仍在DOM中,用于判斷頁面是否刷新9element_to_be_selected節(jié)點可選擇,傳入節(jié)點對象10element_located_to_be_selected節(jié)點可選擇,傳入元組類型數(shù)據(jù)具體用法請參考案例1-3-4。七、Selenium中延時等待1)要使用延時等待,需先引入幾個模塊,分別是:frommon.byimportByfromselenium.webdriver.support.uiimportWebDriverWaitfromselenium.webdriver.supportimportexpected_conditionsasEC2)在創(chuàng)建瀏覽器對象browser后,可創(chuàng)建等待對象wait:

wait=WebDriverWait(browser,10)其中,10表示最長等待時間,單位為秒。超過這個時間沒有達到等待條件會拋出TimeoutException異常。程序中的用法七、Selenium中延時等待3)設定延時等待條件。延時條件都是針對具體的元素設定的,例如在案例1-3-4中針對“跳轉框”設定的等待條件是“當頁面加載出了該元素”,代碼是:input_page=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,"#J_bottomPage>span.p-skip>input")))wait.until()方法還有一個重要的作用:可以返回元素本身,即當?shù)却龡l件達成后,會返回元素的引用。相當于具有find_element()方法的作用。程序中的用法八、任務實踐實現(xiàn)思路開始Selenium初始化聲明瀏覽器對象訪問某電商網(wǎng)站首頁查找搜索框、輸入關鍵字回車跳轉到商品瀏覽頁面循環(huán)變量i=1(用于控制當前爬取的頁碼)控制垂直滾動條按照正常瀏覽速度下劃到底頁面底部跳轉框加載完成否?循環(huán)提取當前頁面商品數(shù)據(jù)(60件),每提取一件商品數(shù)據(jù)就保存到文件處理完當前頁后將循環(huán)變量i增加1在跳轉框中輸入i,跳轉到下一頁i在最大爬取頁碼范圍內與否?爬取結束NYYN任務1認識網(wǎng)絡爬蟲任務2數(shù)據(jù)解析任務3采集動態(tài)渲染網(wǎng)頁的數(shù)據(jù)任務4使用Scrapy框架網(wǎng)絡數(shù)據(jù)采集利器:網(wǎng)絡爬蟲CONTENTS任務4-案例導入以網(wǎng)站(/)為例,我們來學習使用Scrapy框架從其網(wǎng)頁HTML源碼中解析出引言數(shù)據(jù)。任務4-任務導航一、Scrapy框架簡介Scrapy框架是由ScrapyEngine、Scheduler、Downloader、Spiders、ItemPipeline、DownloaderMiddlewares、SpiderMiddlewares這些模塊組成的。那么在框架中這些模塊起什么作用呢?框架的運作流程又是如何的呢?帶著這兩個問題,我們用一張表和一張圖給大家簡要說明一下。請先看表1-4-1,是關于Scrapy框架中各模塊的簡介。一、Scrapy框架簡介表1-4-1Scrapy框架各模塊的簡介模塊中文名作用及特點是否需要編程ScrapyEngine引擎總指揮角色,負責數(shù)據(jù)和信號在不同部件之間的傳遞。Scrapy框架已經(jīng)實現(xiàn)。Scheduler調度器存放引擎發(fā)送的Requests請求數(shù)據(jù)列表,并負責調度當前要處理的請求。Scrapy框架已經(jīng)實現(xiàn)。Downloader下載器根據(jù)引擎發(fā)送的Request請求向站點請求,并將站點的相應結果封裝為Response對象返回給引擎。Scrapy框架已經(jīng)實現(xiàn)。Spider爬蟲處理引擎發(fā)送來的Response對象,從站提取出需要的數(shù)據(jù),提取新的要處理的URL(如果有)并交給引擎。需要程序員編寫代碼實現(xiàn);有時一個項目還需要編寫多個Spider代碼。ItemPipeline管道處理引擎?zhèn)魉瓦^來的數(shù)據(jù)。例如負責將數(shù)據(jù)存儲到如數(shù)據(jù)庫、或文件等。需要程序員編寫代碼實現(xiàn)DownloaderMiddlewares下載中間件可以自定義的下載器的擴展,比如設置代理、請求時采用Selenium驅動瀏覽器等。一般情況下不用編寫,只在需要相應功能時才要編寫。SpiderMiddlewares爬蟲中間件可以自定義Requests請求和進行Response過濾。一般情況下不用編寫,只在需要相應功能時才要編寫。一、Scrapy框架簡介圖1-4-3Scrapy框架的運作流程二、Scrapy框架的安裝與開發(fā)環(huán)境配置在windows的命令窗口中運行安裝命令(已安裝python3):pipinstall-i/pypi/simple/scrapy(一)在windows中安裝scrapy(二)在windows中安裝scrapy在PyCharm中打開Scrapy項目(方法見下一節(jié)中“在PyCharm中打開項目并配置開發(fā)環(huán)境”的內容)。然后單擊“File”→“Settings...”菜單,彈出“Settings”對話框,如圖1-4-5所示。三、創(chuàng)建Scrapy項目在windows的命令窗口中運行創(chuàng)建項目的命令:scrapystartprojectquotesproject其中,quotesproject為項目名稱。(一)通過命令行創(chuàng)建項目文件夾在執(zhí)行命令前注意先切換到指定目錄下,這樣創(chuàng)建的項目文件夾就會放在我們希望的位置。執(zhí)行命令后如果出現(xiàn)“Youcanstartyourfirstspiderwith:……”表示已創(chuàng)建成功。三、創(chuàng)建Scrapy項目先確定起始Spider的名字,還有該爬蟲項目允許爬取的域名。以本次任務為例,Spider名字為“quotes”,允許爬取的域名為“”,那么創(chuàng)建起始爬蟲命令如下:cdquotesprojectscrapygenspiderquotes(二)創(chuàng)建起始爬蟲文件三、創(chuàng)建Scrapy項目(1)先在PyCharm中打開項目。(三)在PyCharm中配置開發(fā)環(huán)境(2)在Pycharm中打開項目后,接下來請按照上節(jié)的第2項“在PyCharm中安裝scrapy”的內容來配置開發(fā)環(huán)境。四、Scrapy項目開發(fā)入門(1)scrapy.cfg:Scrapy項目的配置文件,定義了項目的配置文件路徑、部署的相關信息。(2)items.py:用來定義Item數(shù)據(jù)結構,項目中所有自定義的Item類都應放在此文件里。(3)pipelines.py:在該文件中編寫ItemPipeline的代碼,所有的管道類都寫在這里。(4)settings.py:定義了項目的全局配置。(5)middlewares.py:在該文件中放SpiderMiddlewares和DownloaderMiddlewares的實現(xiàn)。(6)spiders:文件夾,其內包含一個個的Spider的實現(xiàn),每個Spider都編寫在一個單獨的.py文件中,并且其中有唯一一個Spider作為項目的起始Spider。(一)項目文件夾結構四、Scrapy項目開發(fā)入門Spider是需要我們編寫的類,Scrapy引擎會使用它來從Response對象中提取出需要的數(shù)據(jù)。一個項目中可以有若干個Spider類,每個Spider負責按照指定方式從對應的Response對象中解析出數(shù)據(jù),并將數(shù)據(jù)保存到Item對象中,然后再傳送給引擎,由引擎交給管道類去做后續(xù)處理。前面創(chuàng)建了起始爬蟲quotes,在項目文件夾中打開“\quotesproject\spiders\quotes.py”文件。importscrapyclassQuotesSpider(scrapy.Spider):name="quotes"allowed_domains=[""]start_urls=[""]

defparse(self,response):pass(二)爬蟲Spider爬蟲的名字爬蟲允許爬取的域名范圍爬蟲的起始URL爬蟲從response解析數(shù)據(jù)的方法四、Scrapy項目開發(fā)入門Item是保存爬蟲數(shù)據(jù)的容器。它的使用方法和字典類似,不過相比字典多了額外的保護機制可以避免拼寫錯誤或者定義字段錯誤。Item類是在項目里的items.py文件中編寫的。創(chuàng)建的Item類都需繼承scrapy.Item類,并且定義類型為scrapy.Field的字段。importscrapyclassQuoteItem(scrapy.Item):text=scrapy.Field()author=scrapy.Field()tags=scrapy.Field()(三)保持數(shù)據(jù)的容器(Item類)聲明Item類,并繼承自scrapy.Item創(chuàng)建了text字段用于保存引言內容創(chuàng)建了author字段用于保存引言作者創(chuàng)建了tags字段用于保存引言分類defparse(self,response):quotes=response.css('.quote')forquoteinquotes:text=quote.css('.text::text').extract_first()author=quote.css('.author::text').extract_first()text=quote.css('.tags>.tag::text').extract()四、Scrapy項目開發(fā)入門解析站點的響應Response數(shù)據(jù)是在爬蟲Spider的parse()方法中編寫代碼實現(xiàn)的。defparse(self,response):該方法的參數(shù)response代表服務器的響應對象。它包含了請求的網(wǎng)頁數(shù)據(jù)。解析提取其中數(shù)據(jù)主要采用CSS選擇器或Xpath選擇器實現(xiàn)。例如:(四)解析Response數(shù)據(jù)用css選擇器選中一條引言所在的div元素提取引言的內容文本,從得到的對象中用extract_first()提取出文字。提取引言的分類文本,從得到的對象中用extract()方法提取出分類(列表對象)。四、Scrapy項目開發(fā)入門

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論