天天看點

基于python的網絡爬蟲初探網絡爬蟲概述

@TOC基于python的網絡爬蟲學習筆記1

網絡爬蟲概述

網絡爬蟲主要包含兩個任務:1.下載下傳目标網頁;2.從目标網頁提取需要的資料。

網絡爬蟲的主要類型:1.通用網絡爬蟲;2.聚焦網絡爬蟲;3.增量式網絡爬蟲;4.深層頁面爬蟲。

簡易網絡爬蟲架構:1.URL管理器;2.網頁下載下傳器;3.網頁解析器;4.輸出管理器。

網絡爬蟲常用工具:python

1.python中實作網絡爬蟲工具包

(1) python中實作HTTP請求:

常用的主要有兩個庫:

1)Urllib庫。Urllib庫是python内置的HTTP請求庫,可以直接使用。

2)Requests庫。Requests庫是用python語言編寫的。它比更加友善,使用它可以節約我們大量的工作,完全滿足HTTP的測試需求。簡單易用。

(2) python實作網頁解析:

網頁解析器,即主要用于從HTML網頁資訊中提取需要的、有價值的的資料和連結。python中主要有三種工具:

1)正規表達式。描述一種字元串比對的模式,提取效率高但表達式不直覺,寫起來比較複雜。

2)Lxml庫。使用的是XPath文法,可在XML文檔中對元素和屬性進行周遊。直覺易懂,配合Chrome或Firefox浏覽器寫起來簡單、運作效率高。

3)Beautiful Soup。Beautiful Soup可以從HTML或XML檔案中提取資料的python庫。簡單易學,但比前兩種解析速度慢。

(3) python爬蟲架構:

幫助實作爬蟲項目的半成品。結合具體應用場景調用架構的接口,通過少量的代碼實作一個爬蟲項目。python中常見的有三種:

1)Scrapy架構。Scrapy架構是python中最著名、最受歡迎的爬蟲架構,相對成熟。它是為了爬取網站資料、提取結構性資料而編寫,也可以用于資料挖掘、資訊處理或是存儲曆史資料等一系列程式中。

2)Pyspider架構。Pyspider架構是國人編寫的、用python實作的。可在浏覽器界面上進行腳本的編寫、功能的排程和爬取結果的實時檢視,後端利用常用資料庫進行爬取結果的存儲,還能定時設定任務以及任務優先級等。

3)Cola架構。Cola架構是一個分布式的爬蟲架構,使用者隻需編寫幾個特定的函數,而不需關注分布式運作的細節,任務會自動配置設定到多台機器上,整個過程對于使用者是透明的。

2.python中實作網絡爬蟲基本文法

(1) Requests庫實作HTTP請求:

從用戶端到伺服器端的請求消息。HTTP請求由請求方法、請求頭部、請求正文3部分組成。

1)請求方法:

GET方法:請求指定頁面資訊,并傳回實體主體。

POST方法:向指定資源送出資料進行處理請求,資料被包含在請求體中。

平時打開一個網站一般使用的是GET方法,如果涉及向網站送出資料(如登陸),就用POST方法。除此之外,還有一些其他的請求方法,如:HEAD 、PUT、 DELETE 、CONNECT 、OPTIONS 、TRACE等,實際爬蟲中較少用到。

2)請求頭部:

請求頭部包含很多有關用戶端環境和請求正文的有用資訊。一般網站伺服器最常用的反爬蟲措施就是通過讀取請求頭部的使用者代理(user-agent)資訊,判斷該請求是來自正常的浏覽器還是爬蟲。

打開某浏覽器—空白處右鍵—檢查—network—重新整理頁面----。。。。

3)Request庫請求方法:

在這裡插入代碼片
import requests
#擷取豆瓣首頁。得到響應對象
response = requests.get('https://www.douban.com/')
#擷取文本方式的響應體内容
text_r = response.text
#檢視響應體編碼方式
encode_type = response.encoding
#設定響應體編碼方式
response.encoding = 'utf-8'
#檢視網頁源碼
org_code = response.content
#響應狀态碼,常見狀态碼及含義:200---請求成功;301---資源被永久轉移到其它URL;
#404---請求的資源或網頁不存在;500---内部伺服器錯誤。
status = response.status_code
#定制請求頭部,字典dict形式
headers = {
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36’
}
#檢視設定的請求頭部
head = response.request.headers
#或者
head = response.headers
#重定向
response.history
#逾時設定,表示若在timeout=3秒内收不到豆瓣伺服器的響應,就會抛出timeout異常。
response = requests.get('https://www.douban.com/',timeout = 3)
#檢視實際請求的URL
response.url
#傳遞url參數:
payload = {'q' : 'python' , 'cat' : '1001'}
r = requests.get('https://www.douban.com/search', params = payload)
r.url
#https://www.douban.com/search?q=python&cat=1001
           

(2) Lxml實作網頁解析:

Lxml大部分功能存在于etree下,下面主要使用etree這個子產品實作網頁解析。

#加載所需包
import requests
from lxml import etree
#定義一個HTML源碼作為示例,如下所示:
​html="""
   <div>
        <ul>
            <li class="item-0"><a href="link1.html" target="_blank" rel="external nofollow" >first item</a></li>
            <li class="item-1"><a href="link2.html" target="_blank" rel="external nofollow" >second item</a></li>
            <li class="item-inactive"><a href="link3.html" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >third item</a></li>
            <li class="item-1"><a href="link4.html" target="_blank" rel="external nofollow" >fourth item</a></li>
            <li class="item-0"><a href="link5.html" target="_blank" rel="external nofollow" >fifth item</a></li>
            <li class="else-0">else item</li>
            another item
        </ul>
    </div>
"""
           

1)通過路徑查找元素

XPath文法實際上就是使用這種層級的路徑來找到相應元素的,類似與人們常使用的位址,從大的犯罪一直縮小到具體的某個位址上。但如果要找的某個元素或位址是獨一無二的,可以直接指明這個位址,不需要層級關系來一層一層的定位。

#利用HTML源碼初始化etree
selector = etree.HTML(html)
#查找所有的<li>标簽,XPath用//表示從根節點開始查找
all_li = selector.xpath('//div/ul/li')
#因為源碼中<ul>标簽是唯一的是以也可以從根節點取定位ul開始查找
all_li = selector.xpath('//ul/li')
#定位某一個<li>标簽,eg:第一個(**XPath中的序号是從1開始的,這與python切片的初始編号不同)
li_1 = selector.xpath('//ul/li[1]')
#現在提取第一個<li>标簽下的<a>标簽裡面的文本“first item”
li_1_text =  selector.xpath('//ul/li[1]/a/text()') # [“first item”]
#li_1_text  是清單形式輸出,若要輸出元素則如下:
li_1_text_a =  selector.xpath('//ul/li[1]/a/text()')[0] # “first item”
           

2)通過屬性查找元素

在htm中有< li class=“item-0”>、< a href=“link1.html” >這樣的代碼,這裡的class 和href 分别是标簽< li >和< a >的屬性。是以,也可通過屬性來定位元素。

#查找第三個<li>
li_3 = selector.xpath('//ul/li[@class="item-inactive"]')
#因為class="item-inactive" 在源碼中是唯一的,是以,也可如下:(*表示任意字元)
li_3 = selector.xpath('//*[@class="item-inactive"]')
#接下來提取a 标簽裡面的文本
li_3_text = selector.xpath('//*[@class="item-inactive"]/a/text()')
#上述既可以在單引号裡面使用雙引号,也可以在雙引号裡面使用單引号,但不可同時使用單引号或者雙引号。
#li_3_text也可等價于如下:
li_3_a_text = selector.xpath('//*[@href="link3.html" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" ]/text()')
#提取li_3中href的屬性值,而不是标簽a的文本值,如下:
li_3_a_label =  selector.xpath('//ul/li[3]/a/@href') 
#取出所有li标簽的class屬性
all_li_class = selector.xpath('//li/@class')
           

3)XPath的其他用法

部分比對:starts-with; 相對路徑 ; string()提取代碼段所有文本

#提取前5個li 标簽
li_before_5 = selector.xpath('//li[starts-with(@class,"item-")]')
#提取第三個li标簽下a标簽的文本,相對路徑,接着li标簽繼續向下查找
li_3_text = li_before_5.xpath('a[3]/text()')
#提取ul這一層本層的文本
ul_text = selector.xpath('//ul/text()')
#提取ul 裡面各層級的所有文本
all_text = selector.xpath('string(//ul)')
#使用清單推導式取出所有的文本
[s.strip() for s in all_text.strip().split('\n')]