python 3.x 爬蟲基礎
python 3.x 爬蟲基礎---http headers詳解
python 3.x 爬蟲基礎---Requersts,BeautifulSoup4(bs4)
前言
其實前兩章都是python內置的爬蟲函數,大家都知道python有強大的第三方庫,今天我們就來說一下requests,BeautifulSoup4,selenium,lxml ,順便正則re也會在這篇文章中提及。
Requersts
參考文檔:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html
python實現的簡單易用的HTTP庫(第三方庫記得去導入)你不需要手動為 URL 添加查詢字串,也不需要對 POST 數據進行表單編碼。Keep-alive 和 HTTP 連接池的功能是 100% 自動化的,一切動力都來自於根植在 Requests 內部的 urllib3,使用起來比urllib簡潔很多。上面的得文檔有詳細的介紹,所以如果想系統的學習就直接觀看文檔即可。
操作屬性
import requests response = requests.get('http://www.baidu.com') print('文本形式的網頁源碼') print(response.text) print('二進制流形式打印') print(response.content) print('返回JSON格式,可能拋出異常') print(response.json) print('狀態碼') print(response.status_code) print('請求url') print(response.url) print('頭信息') print(response.headers) print('cookie信息') print(response.cookies)
看一下運行結果:
傳遞參數
import requests payload = {'key1': 'value1', 'key2': 'value2', 'key3': None} r = requests.get('http://httpbin.org/get', params=payload) print(r.url)
運行結果:
傳遞headers
這個在python 3.x 爬蟲基礎---http headers詳解 有詳細的介紹不管是urllib還是request headers都是至關重要的,在這不過多敘述有興趣的自己去看一下吧。
請求方式
requests.get('http://httpbin.org/get') requests.post('http://httpbin.org/post') requests.put('http://httpbin.org/put') requests.delete('http://httpbin.org/delete') requests.head('http://httpbin.org/get') requests.options('http://httpbin.org/get')
post訪問
通常,你想要發送一些編碼為表單形式的數據—非常像一個HTML表單。 要實現這個,只需簡單地傳遞一個字典給 data 參數。你的數據字典 在發出請求時會自動編碼為表單形式:
import requests payload = {'key1': 'value1', 'key2': 'value2'} r = requests.post("http://httpbin.org/post", data=payload) print(r.text)
運行結果:
傳遞文件:
import requests url = 'http://httpbin.org/post' files = {'file': open('wyl.xls', 'rb')} r = requests.post(url, files=files)
這個方式對你傳遞的復雜參數有很好的控制。
傳遞字符串:
import requests import json url = 'https://xxxxxxxx' payload = {'some': 'data'} r = requests.post(url, data=json.dumps(payload)) #或者 r = requests.post(url, json=payload)
提示:選擇適當的http訪問。
超時設置
requests.get('http://xxxxx.com', timeout=1)
注:timeout
僅對連接過程有效,與響應體的下載無關。 timeout
並不是整個下載響應的時間限制,而是如果服務器在 timeout
秒內沒有應答,將會引發一個異常。
代理
import requests proxies = { 'http': 'http://10.10.1.10:3128', 'https': 'http://10.10.1.10:1080', } requests.get('http://xxxx.com', proxies=proxies)
防爬蟲會涉及到ip限制,所以ip代理在爬蟲中會常用到,還有vpn代理等等吧。
重定向與請求歷史
默認情況下,除了 HEAD, Requests 會自動處理所有重定向。可以使用響應對象的 history
方法來追蹤重定向,head可以通過 allow_redirects
參數禁用重定向處理。
import requests s=requests.get('http://github.com') print(s.url) print(s.status_code) r=requests.get('http://github.com', allow_redirects=False) print(r.url) print(r.history) r=requests.head('http://github.com'); print(r.url) print(r.status_code) r=requests.head('http://github.com', allow_redirects=True) print(r.url) print(r.history)
運行結果:
異常處理
所有Requests顯式拋出的異常都繼承自 requests.exceptions.RequestException
import requests from requests.exceptions import ReadTimeout,HTTPError,RequestException try: response = requests.get('http://www.baidu.com',timeout=0.5) print(response.status_code) except ReadTimeout: print('timeout') except HTTPError: print('httperror') except RequestException: print('reqerror')
HTTPError
:如果 HTTP 請求返回了不成功的狀態碼
Timeout
:請求超時
ConnectionError
:遇到網絡問題(如:DNS 查詢失敗、拒絕連接等)
TooManyRedirects
:若請求超過了設定的最大重定向次數
RequestException:所有的requerst 異常
requests登陸的幾種方法
通過賬號與密碼
loginurl='https://xxxxx.com/check' formData={'username':'*****', 'password':'*****'} headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/52.0'} res=req.post(loginurl,data=formData,headers=headers)
通過cookies
raw_cookies="k1=v1; k2=v2; k3=v3; cookies={} for line in raw_cookies.split(';'): key,value=line.split('=',1) cookies[key]=value loginurl='http://xxxxxx.com' res=req.post(loginurl,cookies=cookies) print res.content "訪問其它的頁面" logi1="http://xxxxx.htm" print req.post(logi1,cookies=cookies).content
其中的cookies獲取后將cookies的值以字典的方式存儲,然后進行使用
通過session
import requests as req s=req.Session() param={'username':'****', 'password':'***'} url='https://xxxxxx' r=s.post(url,data=param,verify=False) #登錄獲取登錄后的session print r.content print s.get('http://xxxxxxx',verify=False).content #通過session訪問其它url
如果有ssl認證,可以在post的時候,加入認證的參數,取消ssl的認證校驗 requests.post(url,data=dataform,verify=False)
BeautifulSoup4(bs4)
參考文檔:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
是一個可以從HTML或XML文件中提取數據的Python庫.它能夠通過你喜歡的轉換器實現慣用的文檔導航,查找,修改文檔的方式.urllib或者request請求完之后,就要對其操作,那么下面就來操作吧。其實可以把它理解為js/css中的選擇器來使用。
解析器
Beautiful Soup支持Python標准庫中的HTML解析器,還支持一些第三方的解析器,其中一個是LXML ,后面會有介紹。
對象的種類
Beautiful Soup將復雜HTML文檔轉換成一個復雜的樹形結構,每個節點都是Python對象,所有對象可以歸納為4種: Tag , NavigableString , BeautifulSoup , Comment
#1.tag
此對象與html和xml 中的tag相同
soup = BeautifulSoup('<div class="className">wangyanling</div>') tag = soup.div print('tag 對象輸出:') print(tag) print('查看類型') print(type(tag)) print('#獲取tag的名字') print(tag.name) print('#Attributes') print('#Attributes:獲取tag的屬性值 注tag是有多個屬性') print(tag['class']) print('添加屬性') tag['id']='wylId' print(tag) print('#刪除屬性') del tag['class'] print(tag) print('#多值屬性') css_soup = BeautifulSoup('<p class="body strikeout"></p>') print(css_soup.p['class']) print('#不明確的多值屬性') id_soup = BeautifulSoup('<p id="my id"></p>') print(id_soup.p['id']) print('# 重新賦值') print('#重復的值會進行合並') rel_soup = BeautifulSoup('<p>Back to the <a rel="index">homepage</a></p>') print(rel_soup.a['rel']) rel_soup.a['rel'] = ['index', 'contents'] print(rel_soup.p) print('xml 多值屬性') '''xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml') print(xml_soup.p['class'])'''
輸出結果:
#2.NavigableString
操作標簽嚇得字符串,我們就要用到NavigableString 類
soup = BeautifulSoup('<b class="index">wyl good</b>') print('soup.string的類型(NavigableString)') print(soup.string) print(type(soup.string)) print('替換字符串') soup.string.replace_with("王延領") print(soup)
輸出結果:
注:一個字符串不能包含其它內容(tag能夠包含字符串或是其它tag),字符串不支持 .contents 或 .string 屬性或 find() 方法.
#3.BeautifulSoup
表示的是一個文檔的全部內容,大部分時候,可以把它當作 Tag 對象。它支持 遍歷文檔樹 和 搜索文檔樹 中描述的大部分的方法.他是沒有name合attribute的。
#4.Comment
以上三個對象幾乎包換了你所有html與xml的內容,但是你是不是覺得還有一個東西沒有涉及到,那就是html xml不編輯的注解。
markup = "<b><!--我是一個注釋不要意思--></b>" soup = BeautifulSoup(markup) comment = soup.b.string print('html中的注釋') print(comment) print(type(comment))
輸出結果:
看輸出Comment是不是一個特殊的NavigableString管他呢。
遍歷文檔樹
上面有提到遍歷文檔樹與搜索文檔樹,那么就來一起學習一下。其實從名字就能知道踏實去循環遍歷獲取html xml內容的。
我們可以把它分為子節點,父節點,兄弟節點,回退與前進是不是css/js選擇器的感覺其實差不多。
為了方便我寫了一些html

html_doc = """ <html> <head> <title>The Dormouse's story</title> <stype> .body{ color:red; } </stype> </head> <p class="title"><b>這是一個不太好的html</b></p> <p class="story">這是一個段落 <a href="http:http://www.cnblogs.com/kmonkeywyl/p/8482962.html%20" id="link1">python 3.x 爬蟲基礎---常用第三方庫</a>, <a href="http://www.cnblogs.com/kmonkeywyl/p/8458442.html" class="sister" id="link2">python 3.x 爬蟲基礎---Urllib詳解</a> <a href="http://www.cnblogs.com/kmonkeywyl/p/8435533.html" class="sister" id="link3">python 3.x 爬蟲基礎---http headers詳解</a>; </p> <p class="story">...</p> """
#1.子節點
soup = BeautifulSoup(html_doc) print('1.利用tag的name獲取信息') print(soup.head) print('2.獲取第一個p標簽') print(soup.p) print('3.獲取第一p下的a') print(soup.p.b) print('4.tag的 .contents 屬性可以將tag的子節點以列表的方式輸出') head_tag = soup.head print(head_tag) print(head_tag.contents) print('5.通過tag的 .children 生成器,可以對tag的子節點進行循環') i=0 for child in head_tag.children: print(i) i=i+1 print(child) print('6.descendants 操作soup的子孫節點(包括字符串)') for child in head_tag.descendants: print(i) i=i+1 print(child) print('7.如果tag只有一個 NavigableString 類型子節點,那么這個tag可以使用 .string 得到子節點') s_titl=soup.title print(s_titl.string) print('8.如果有多個字符串可以用strings循環獲得') for string in soup.strings: print(repr(string)) print('9.stripped_strings去除空格') for string in soup.stripped_strings: print(repr(string))
#2.父節點
print('通過 .parent 屬性來獲取某個元素的父節點') soup = BeautifulSoup(html_doc) title_tag = soup.title print(title_tag) print('title 父節點') print(title_tag.parent) print('html 的父節點') html_tag = soup.html print(type(html_tag.parent)) print('BeautifulSoup的父節點 ') print(soup.prent) print('通過元素的 .parents 屬性可以遞歸得到元素的所有父輩節點') link = soup.a for parent in link.parents: if parent is None: print(parent) else: print(parent.name)
輸出結果:
#3.兄弟節點
sibling_soup = BeautifulSoup("<a><b>text1</b><c>text2</c></a>") print('next_sibling|previous_sibling 尋找兄弟節點') print(sibling_soup.prettify()) print(sibling_soup.b.next_sibling) print(sibling_soup.c.previous_sibling) print('通過 .next_siblings 和 .previous_siblings 屬性可以對當前節點的兄弟節點迭代輸出') soup = BeautifulSoup(html_doc) for sibling in soup.a.next_siblings: print(repr(sibling))
輸出結果:
#4.回退與前進
HTML解析器把這段字符串轉換成一連串的事件: “打開<html>標簽”,”打開一個<head>標簽”,”打開一個<title>標簽”,”添加一段字符串”,”關閉<title>標簽”,”打開<p>標簽”,等等.Beautiful Soup提供了重現解析器初始化過程的方法.
通過 .next_elements 和 .previous_elements 的迭代器就可以向前或向后訪問文檔的解析內容,就好像文檔正在被解析一樣:
soup = BeautifulSoup(html_doc) for element in soup.a.next_elements: print(repr(element))
搜索文檔樹
未完待續