1. 程式人生 > >Python3爬蟲1

Python3爬蟲1

  1. 爬蟲原理:請求網站並提取資料的自動化程式
    1. 通用爬蟲:搜尋引擎爬蟲;聚焦爬蟲:獲取某一垂直領域的資料或者有明確的檢索需求,需要過濾掉一些無用的資訊
    2. HTTP協議:用於從WWW伺服器傳輸文字到本地瀏覽器的傳送協議;HTTPS協議是加密的超文字傳輸協議
      1. HTTP主要請求方式
        1. GET請求:是以實體的方式得到由請求URL所指定資源的資訊
        2. POST請求:用來向目的服務發出請求,並且帶上某些資訊,如果使用者輸入的資料包敏感資料,那麼使用POST為好
        3. PUT請求:請求伺服器儲存一個資源,通常要指定儲存的位置
        4. DELETE請求:請求伺服器刪除一個資源
        5. HEAD請求:請求獲取對應的HTTP頭資訊
        6. OPTIONS請求:可以獲得當前URL所支援的請求型別
      2. HTTP頭部資訊:HTTP頭部資訊由眾多的頭域組成,每個頭域由一個域名,冒號和域值三部分組成;F12->Network->Doc即主要請求,其中的Headers分頁即請求頭,包含請求頭部資訊
        1. Request Method代表的是請求方式,HTTP/1.1表示使用HTTP1.1協議標準,200OK說明請求成功
        2. Host頭域,指定請求資源的Intenet主機和埠號,必須表示請求URL的原始伺服器或閘道器的位置;即網址
        3. User_Agent頭域,裡面包含發出請求的使用者資訊,其最終由使用的瀏覽器型號,版本和作業系統的資訊。這個頭域經常用來作為反爬蟲的措施,普通爬蟲不包含User_Agent
        4. Accept:瀏覽器支援的內容型別
        5. Accept-Encoding:瀏覽器支援的語言型別
        6. Connection:客戶端和伺服器的連線型別,對應的欄位值有keep-alive永續性連線和close單方面管理連線
        7. Referer來源網址地址
    3. 爬蟲流程
      1. 網頁特徵
        1. 網頁都有自己唯一的URL(統一資源定位符)來進行定位
        2. 網頁都使用HTML (超文字標記語言)來描述頁面資訊
        3. 網頁都使用HTTP/HTTPS(超文字傳輸協議)協議來傳輸HTML資料
      2. 基本流程
        1. 發起請求:通過HTTP庫向目標站點發起請求,即傳送一個Request,請求可以包含額外的headers等資訊,等待伺服器響應
        2. 獲取響應內容:如果伺服器能正常響應,會得到一個Response,Response的內容便是所要獲取的頁面內容,型別可能有HTML,Json字串,二進位制資料(如圖片視訊)等型別
        3. 解析內容:得到的內容可能是:
          1. HTML,可以用正則表示式、網頁解析庫進行解析
          2. Json,可以直接轉為Json物件解析
          3. 二進位制資料,可以做儲存或者進一步的處理
        4. 儲存資料:儲存形式多樣,可以存為文字,也可以儲存至資料庫,或者儲存特定格式的檔案
  2. 爬蟲與反爬蟲
    1. 反爬蟲機制:
      1. 分析使用者請求的Headers資訊,網站中應用的最多
      2. 驗證使用者行為,在短時間內是否頻繁訪問網站
      3. 動態頁面增加爬蟲難度
    2. 應對策略
      1. 構造使用者請求的Headers資訊
      2. 使用代理伺服器並經常切換代理伺服器
      3. 利用工具軟體,例如selenium+phantomJs
  3. 請求與響應
    1. 請求Request:瀏覽器傳送訊息給該網址所在的伺服器
      1. 主要方式有GET和POST
      2. URL統一資源定位符
      3. 請求頭部資訊包括User-Agent,Host,Cookies
      4. 請求時能攜帶額外的資料,即POST
    2. 響應Response:伺服器收到瀏覽器傳送的訊息後,能夠根據瀏覽器傳送訊息的內容,做相應處理,然後把訊息回傳給瀏覽器
      1. 響應狀態:200成功,301跳轉,403forbidden禁止訪問,404找不到頁面,502伺服器錯誤
      2. 響應頭,如內容型別,內容長度,伺服器資訊,設定Cookie(使用者行為)等
      3. 響應體包含最主要的請求資源的內容
    3. 瀏覽器收到伺服器的Response資訊後,會對資訊進行相應處理,然後展示
  4. 資料選擇和處理
    1. 抓取資料型別:
      1. 網頁文字HTML文件,Json格式文字
      2. 圖片的二進位制檔案
      3. 視訊的二進位制檔案及其他
    2. 解析方式
      1. 直接處理
      2. Json解析
      3. 正則表示式
      4. BeautifulSoup
      5. PyQuery
      6. XPath
    3. JavaScript渲染問題
      1. 分析Ajax
      2. Selenium/WebDriver
      3. Splash
      4. PyV8/Ghost.py
    4. 儲存資料
      1. 文字
      2. 關係型mysql和非關係型Redis資料庫
      3. 二進位制檔案,如圖片,視訊
  5. *爬蟲工具gooseeker,八爪魚等
  1. 爬蟲基本請求庫Urllib:Urllib是python內建的HTTP請求庫,也是python爬蟲的基礎庫
    1. *Urllib.request請求模組,Urllib.Error異常處理模組,Urllib.parse解析
    2. response=urllib.request.urlopen(url,data,timeout)->response.read().decode('')
      1. 前端知識:<head>包含的<meta>內有content="charset="即網頁編碼屬性
      2. url網址
      3. data訪問網站時傳送的資料包,預設null
      4. timeout等待時長
      5. decode('')解碼,把位元組流形式資料以網頁的字元格式轉化為字串
    3. urllib.request.urlretrieve(url,filename='*.html')直接儲存html文件
      1. **每次操作都會有快取,多次爬蟲必須加上清除快取的步驟urllib.request.urlcleanup()
    4. 搜尋引擎框中的中文會自動轉化為ASCII碼進行搜尋,所以在構造搜尋網頁url時,urllib.request.quote(keyword)將搜尋關鍵字先轉化為編碼
    5. POST資料傳送
      1. urllib.parse.urlencode({}).encode('utf-8')HTML中post方法表單中的輸入框的標籤name對應想要上傳值的字典;用encode()將字串轉化為相應編碼格式的二進位制位元組流形式->urllib.request.urlopen(url,data)中的data即urllib.parse.urlencode({}).encode('utf-8')想要上傳的位元組流資料
      2. encode編碼,decode解碼
    6. **urllib高階用法:應對反爬蟲設定
      1. 設定Headers
        1. urllib.request.urlopen(urllib.request.Request(url=url,headers={'User-Agent':''})).read().decode();urllib.request.Request()即設定請求細節,放入headers的User-Agent瀏覽器資訊
      2. Proxy(代理)的設定
        1. urllib.request.install_opener(urllib.request.build_opener(urllib.request.ProxyHandler({'http':proxy_addr})))設定全域性代理伺服器,傳入proxy_addr需要加上埠
      3. Timeout設定urllib.request.urlopen(url,data,timeout),設定一次請求的等待時間,超過即停止請求
      4. 設定Cookie:Cookie即儲存在瀏覽器中的使用者資訊,可用於繞過登入等,http是無狀態的協議,不儲存登入資訊
        1. import http.cookiejar
        2. 利用登入跳轉頁面url
        3. 寫data登入資訊:urllib.parse.urlencode({}).encode('utf-8')
        4. cjar=http.cookiejar.CookieJar()建立物件
        5. 建立cookie處理器和opener物件,並載入cookie設定urllib.request.install_opener(urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cjar)))
        6. urllib.request.urlopen(url,data)請求得到登入後的頁面
      5. 異常處理
        1. import urllib.error
        2. try:...except urllib.error.URLError|HTTPError as e:...;捕捉到URLError|HTTPError錯誤
  2. 爬蟲高階請求庫Request:import requests
    1. 特點
      1. Requests是用python語言基於urllib編寫的HTTP請求庫
      2. Requests實現HTTP請求非常簡單,更具有Python風格,操作更加人性化
      3. Requests庫是第三方模組,需要額外進行安裝pip install requests
    2. 功能
      1. GET和POST
        1. requests.get(url,headers={'User-Agent':''},cookies={},proxies={},timeout=):get請求
        2. requests.post(url,data={}):post請求,data傳入資料為method="post"的表單中的輸入框的name和對應輸入值
        3. requests.get(url).content|text:請求的位元組流|文字輸出,content.decode可解碼
      2. 響應與編碼:import chardet檢測字串和檔案編碼
        1. requests.get(url).encoding=chardet.detect(requests.get(url).content)['encoding']獲取當前get請求網頁的編碼格式,直接賦值給get請求網頁檔案的編碼
        2. *requests.get(url).status_code獲取當前get請求網頁的響應值
      3. Headers設定
        1. requests.get(url,headers):利用headers的User-Agent瀏覽器資訊
      4. Cookies設定
        1. 登入後介面的headers內的cookie資訊
        2. 傳入的cookies為字典,且先用for迴圈將cookie按;切分,以第一個等號分隔name和value
          1. for i in string.split(';'):name,value=i.strip().split('=',1) cookie[name]=value
        3. requests.get(url,cookies=)利用cookies
      5. 代理設定
        1. 上網查詢代理ip->proxies={'http':'ip:port'}
        2. requests.get(url,proxies={})利用ip
      6. 超時設定
        1. requests.get(url,timeout=)設定請求時間;可用r.status_code檢視頁面請求狀態
  3. 爬蟲解析法Beautiful Soup:是一個可以從HTML或XML檔案中查詢提取資料的Python庫,它能夠通過你喜歡的轉換器實現慣用的文件導航,查詢,修改文件的方式;效率較高上手簡單;pip install bs4;解析器:pip install lxml
    1. *解析器BeautifulSoup(markup,"")
      1. python標準庫:html.parser,python內建
      2. lxml HTML解析器:lxml
      3. lxml XML解析器:xml,唯一支援XML的解析器
      4. html5lib:html5lib,以瀏覽器的方式解析文件,生成HTML5格式的文件
    2. BS將HTML文件轉換成一個樹形結構,每個節點即python物件,物件可分為4類
      1. Tag:標籤<div>,<p>
      2. NavigableString:字元內容操作物件,表示標籤裡面的內容
      3. BeautifulSoup:文件物件,表示的是一個文件的全部內容
      4. Comment:特殊型別的NavigableString,為標籤內註釋的內容
    3. 使用
      1. from bs4 import BeautifulSoup
      2. 建立BS物件:讀取HTML文件或使用HTML格式字串soup=BeautifulSoup(html,"解析器")
      3. 利用BS物件:
        1. *soup.prettify()標準縮排HTML文件輸出
        2. 獲取標籤:soup.標籤名;若有多個同名標籤,只能獲取第一個標籤
        3. 獲取屬性:soup.標籤名.attrs,獲取屬性字典;soup.標籤名['屬性名']
        4. 獲取標籤中間的內容:soup.標籤名.string
          1. 如果標籤中只有一個子標籤,返回子標籤中文字內容
          2. 如果標籤中有多個子標籤,返回None
        5. 遍歷文件樹
          1. 子節點
            1. soup.標籤.contents:匹配標籤的所有子節點及其內容
            2. soup.標籤.children:匹配標籤的子節點列表迭代器,for i in soup.p.children
          2. 父節點
            1. soup.標籤.parent:匹配標籤的父節點及其內容
            2. soup.標籤.parents:匹配標籤的父節點列表迭代器
          3. 兄弟節點
            1. soup.標籤.next|previous_sibling:匹配標籤的同級前|後節點;實測不輸出
            2. soup.標籤.next|previous_siblings匹配標籤的同級前|後所有節點列表迭代器;最好用這個輸出兄弟節點
        6. 搜尋文件樹:
          1. soup.find_all(''):根據標籤名,屬性,內容查詢文件;返回列表
            1. soup.find_all([])多個標籤
            2. soup.find_all(re.compile('d+'))正則表示式查詢,整個標籤中包含d字元
            3. soup.find_all(id='')關鍵字引數查詢
            4. soup.find_all(text='')標籤中間內容匹配,得到的也是標籤的中間內容
            5. for i in soup.find_all('p'):print(i.find_all('a'))巢狀查詢,soup.find_all()也是BS物件
          2. soup.find(''):返回的匹配結果的第一個元素
          3. soup.find_parents()|soup.find_parent():查詢所有|一個父節點
          4. soup.find_next|previous_sibling(s)():查詢後|前所有|一個兄弟節點
          5. soup.find_(all_)next|previous():查詢後|前所有|一個節點
        7. css選擇器:返回list;css檔案即對網頁各個元素進行樣式設計,對網頁元素的多種選擇方法都能在.select('')內使用
          1. css語法:
            1. 標籤名不加修飾
            2. 類名前加.,id名前加#
            3. a,p:找到所有的a和p標籤
            4. a p:找到a標籤下所有的p標籤
            5. soup.select().get_text():獲取標籤中間的文字內容
          2. 操作
            1. soup.select('#id'):id查詢
            2. soup.select('.class'):class查詢
            3. soup.select("a[href='']"):css寫法的查詢
  4. 爬蟲解析法Xpath:Xpath原本是在可擴充套件標記語言XML中進行資料查詢的一種描述語言;對於標記語言都有非常友好的支援,如超文字標記語言HTML
    1. 選取節點
      1. nodename:選取節點的所有子節點
      2. /:起始為/則表示從根節點選取(且為元素的絕對路徑);bookstores/book表示bookstores元素的後代的所有book元素
      3. //:從匹配選擇的當前節點中選擇文件中的節點,不考慮其位置
      4. .:選擇當前節點
      5. ..:選擇當前節點的父節點
      6. @:選擇屬性
      7. 謂語:查詢某個特定的節點或者包含某個指定的值的節點,謂語被嵌在方括號中,類似索引
        1. /bookstores/book[1]:選取屬於bookstores子元素的第一個book元素
        2. /bookstores/book[last()]:選取屬於bookstores子元素的最後一個book元素
        3. /bookstores/book[position()<3]:選取屬於bookstores子元素的前兩個book元素
        4. //title[@lang]:選取所有擁有名為lang的屬性的title元素
        5. /bookstores/book[price>35]:選取bookstores元素中的所有book元素,且其中的price元素>35
        6. /bookstores/book[price>35]/title:選取bookstores元素中的所有book元素,且其中的price元素>35,下面的title元素
      8. 選取未知節點
        1. *:匹配任何元素節點
        2. @*:匹配任何屬性節點
        3. node():匹配任何型別節點
      9. 路徑選取
        1. /bookstores/*:選取bookstores元素的所有子元素
        2. //*:選取文件中的所有元素
        3. //title[@*]:選取所有帶有任何屬性的title元素
        4. //book/title|//book/price:選取book元素的所有title和price元素
        5. //book|//price:選取文件中所有的title和price元素
        6. /bookstores/book/title|//price:選取屬於bookstores元素的book元素的所有title元素和文件中所有的price元素
        7. *div是除法
    2. 操作
      1. from lxml import etree
      2. 初始化構造Xpath解析物件:html=etree.HTML(text),text即HTML文件
      3. 利用Xpath物件
        1. html.xpath('//p'):查詢所有p標籤
        2. html.xpath('//@name'):查詢所有name屬性的值
        3. html.xpath('//*[@name]'):查詢所有包含name 屬性的標籤
        4. html.xpath('//*[@name="desc"]'):)查詢所有包含name屬性,並且name屬性值為desc的標籤
        5. for p in html.xpath('//p'):print(p.text):查詢所有p標籤中間的文字內容,不包含子標籤
        6. for p2 in html.xpath('//p'):print(p2.xpath('string(.)')):查詢多個p標籤下的所有文字內容,包含子標籤中的文字內容
        7. html.xpath('//div/p[3]/@name'):第三個p標籤的name屬性值
  5. 爬蟲解析法正則表示式:上手難但最全面;用規則字串來表達對字串的一種過濾邏輯;
    1. 操作
      1. import re
      2. re.search(pattern,string):pattern為正則表示式'',string是被檢驗的字串'';匹配到的字元和所佔位置,從0開始,左閉右開
      3. re.findall(pattern,string):返回所有匹配正則表示式的字串列表
      4. re.compile(string):返回pattern物件
      5. re.match(pattern,string):從string的第一個字元開始匹配,如果出錯直接返回None
      6. re.sub(pattern,replace,string,count):string中所有匹配的字串轉化為replace,count可以指定次數
    2. 原子:
      1. 普通字元:'yue'
      2. 非列印字元:'\n'換行符等
      3. 通用字元:
        1. \w:匹配字母、數字、下劃線;等價於'[A-Za-z0-9_]'
        2. \W:匹配非字母、數字、下劃線;等價於 '[^A-Za-z0-9_]'
        3. \s:匹配任何空白字元,包括空格、製表符、換頁符
        4. \S:匹配任何非空白字元
        5. \d:匹配一個數字字元
        6. \D:匹配一個非數字字元
        7. \A:匹配字串開始
        8. \Z:匹配字串結束,如果存在換行,只匹配到換行前的結束字元
        9. \z:匹配字串結束
        10. \G:匹配最後匹配完成的位置
        11. \n:匹配換行符
        12. \t:匹配製表符
      4. 元字元:
        1. ^:匹配字串開頭
        2. $:匹配字串結尾
        3. .:匹配除換行符(\n、\r)之外的任何單個字元,當re.DOTALL標記被指定時,可以匹配任意字元;\.匹配點自身
        4. []:原子集
        5. [^]:非原子集,不存在原子集中的字元
        6. *:匹配0或多個的前一個原子,元字元或原子集;貪婪模式,提取後面符合規則的所有字元
        7. +:匹配1或多個的前一個原子,元字元或原子集;貪婪模式
        8. ?:匹配0或1個的前一個原子,元字元或原子集,.*?這裡的?指的是.*;非貪婪模式
        9. |:模式選擇符,設定多個模式,匹配時,可以從中任意一個模式匹配,類似原子集
        10. ():模式單元符,將原子組合成一個大原子使用,用findall則只擷取pattern的()內的字串
        11. {n}:精確匹配n個前面表示式
        12. {n,m}:匹配n到m次由前面正則表示式定義的片段,貪婪模式
      5. 原子表(字符集):[p\wh],定義一組地位平等的原子,然後匹配的時候會取該原子集中任意一個原子進行匹配
    3. 例項:
      1. 匹配.com和.cn字尾的網址:[a-zA-Z]+://[^\s]*[.com|.cn]
      2. 匹配電話號碼:\d{4}-\d{7}|\d{3}-\d{8}
      3. 匹配電子郵箱:
        1. <br><a href='(.*?)'>
        2. [a-zA-Z+-][email protected][a-zA-Z-]+\.\w+([.-]\w+)*,郵箱通用