【MOOC】Python網路爬蟲與資訊提取-北京理工大學-part 1
【第〇周】網路爬蟲之前奏
網路爬蟲”課程內容導學
【第一週】網路爬蟲之規則
1.Requests庫入門
注意:中文文件的內容要稍微比英文文件的更新得慢一些,參考時需要關注兩種文件對應的Requests庫版本。(對於比較簡單的使用方法,我們看中文的就行了)
Requests庫的7個主要方法:
注:這7的方法的後面6個都是由requests.request()函式封裝的。
get方法的使用
對於程式碼r=requests.get(url)
,r為函式返回的Response 物件,該物件包含爬蟲返回的內容。
Response 物件的屬性:
這5個屬性的使用流程:
例子:
>>> import requests
>>> r=requests.get('http://www.baidu.com')
>>> r.status_code
200
>>> r.text
'<!DOCTYPE html>\r\n<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>ç\x99¾åº¦ä¸\x80ä¸\x8bï¼\x8cä½\xa0å°±ç\x9f¥é\x81\x93</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=ç\x99¾åº¦ä¸\x80ä¸\x8b class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>æ\x96°é\x97»</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>å\x9c°å\x9b¾</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>è§\x86é¢\x91</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>è´´å\x90§</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>ç\x99»å½\x95</a> </noscript> <script>document.write(\'<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=\'+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ \'" name="tj_login" class="lb">ç\x99»å½\x95</a>\');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">æ\x9b´å¤\x9a产å\x93\x81</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>å\x85³äº\x8eç\x99¾åº¦</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使ç\x94¨ç\x99¾åº¦å\x89\x8då¿\x85读</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>æ\x84\x8fè§\x81å\x8f\x8dé¦\x88</a> 京ICPè¯\x81030173å\x8f· <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>\r\n'
可以看到,r.text裡面的東西都是亂碼。檢視編碼方式:
>>> r.encoding
'ISO-8859-1'
>>> r.apparent_encoding
'utf-8'
可以這樣理解編碼:網路上的資源都有編碼,沒有適當的編碼,我們就看不懂裡面的內容。
將編碼方式改為:utf-8,可以發現,r.text已經顯示為我們可讀的內容了。
>>> r.encoding='utf-8'
>>> r.text
'<!DOCTYPE html>\r\n<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新聞</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地圖</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>視訊</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>貼吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登入</a> </noscript> <script>document.write(\'<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=\'+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ \'" name="tj_login" class="lb">登入</a>\');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多產品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>關於百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必讀</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意見反饋</a> 京ICP證030173號 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>\r\n'
關於r.encoding和r.apparent_encoding的區別:
如何理解“如果header中不存在charset”:通常我們得到的網頁都是由某個角落的一個伺服器“發出”的,而有些伺服器對網頁的編碼有要求,其所用的編碼就會儲存在網頁header中的charset,而如果沒有charset,那麼Respond物件的編碼就預設為ISO-8859-1。
從上面的那張圖片也可以看到,r.apparent_encoding是根據網頁內容“實實在在”地分析出來的編碼方式,因此其比r.encoding顯得更為靠譜。
爬取網頁的通用程式碼框架
在使用get方法獲得網頁的時候,由於網路連線可能不穩定,所以在使用該方法時需要編寫“異常處理”的程式碼。
requests庫常用的異常:
requests庫中的raise_for_status函式可以幫助我們處理常用的異常:
通用程式碼框架:
測試:
HTTP協議和requests庫方法
重新看到Requests庫的7個主要方法,後面6個一一對應HTTP的相關方法。
下面接介紹HTTP協議:
注:
1.“請求與響應”:使用者端發出請求,伺服器做出響應。
2.“無狀態”:使用者端這次發出的請求和下一次發出的沒有聯絡
3.“應用層協議”:該協議工作在HTTP協議之上
常用URL格式:
HTTP協議對資源的操作:
可以把網路上的資料的所在位置是:雲端,我們可通過get、head操作從雲端獲取資料(可以理解為檔案的讀操作),可通過put、post、patch、delete操作對資料進行修改(可以理解為檔案的寫操作)
舉例:
requests庫主要方法解析
這裡將對requests庫的幾個主要方法的使用方法進行介紹。
對於request函式:
kwargs的13個引數如下:
注:模擬瀏覽器或者手機訪問網頁的方法就是通過headers引數實現的
注:使用file引數可以向伺服器提交檔案
注:當伺服器的響應時間大於timeout值時,request函式會返回超時異常。
注:使用這個引數可以有效地隱藏我們真正的IP地址,可有效地防止爬蟲的逆追蹤
對於get函式
這裡的kwargs和上面的request函式的是一樣的。
前面提高,get、head、post、patch、delete、put這幾個函式都是由request函式定義的,對於進行需要用到的引數,為了方便使用,這些新定義的函式就將這些引數“顯式化”了。
對於head函式
對於post函式
對於patch函式
對於delete函式
單元小結
看了這麼多的使用方法,實際上get方法就是最常用的。對於某些比較複雜的工程,head方法的使用僅次於get,因此重點掌握這兩個方法即可。
討論
儘管Requests庫功能很友好、開發簡單(其實除了import外只需一行主要程式碼),但其效能與專業爬蟲相比還是有一定差距的。請編寫一個小程式,“任意”找個url,測試一下成功爬取100次網頁的時間。(某些網站對於連續爬取頁面將採取遮蔽IP的策略,所以,要避開這類網站。)
請回復程式碼,並給出url及在自己機器上的執行時間。
程式碼:
import requests
import time
def getHTMLText(url):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding=r.apparent_encoding
return r.text
except:
print("Failed")
if __name__ == "__main__":
url = "https://www.baidu.com"
startTime = time.time()
for i in range(100):
getHTMLText(url)
endTime = time.time()
print("the total time is %fs" %(endTime-startTime))
輸出結果:
the total time is 14.201600s
2.網路爬蟲的“盜亦有道”
網路爬蟲引發的問題
首先看網路爬蟲的尺寸分類:
robot協議
例子:
其他例子:
注:若一個網站沒有robots協議,那麼可認為該網站可被爬蟲無限制地爬取。
robot協議的遵守方式
而若我們的爬蟲程式獲取網站資訊的頻率和人類的相似的話,比如一小時獲取一次,這個時候可以不遵守該協議,畢竟對伺服器沒有造成過度的壓力。
單元小結
pass
requests庫網路爬蟲實戰(5個例項)
1.京東商品資訊的爬取:
2.亞馬遜商品頁面的爬取:
與上一個例子不同的是:這裡需要修改headers以讓程式模擬瀏覽器獲取資料。
注意:這裡的除錯方法可以參考,可輸出r.request.headers檢視headers
3.百度/360搜尋關鍵詞提交
搜尋引擎關鍵詞提交介面如下,可以發現只要替換了keyword這個關鍵詞就可以實現關鍵詞的提交了。
4.網路圖片的爬取和儲存
例子:
簡單版本:
詳細版本(相比上面的程式碼,這份程式碼顯得更加穩定):
注:這份程式碼的with…as….語句中的f.close()可以不用加上,該語句會進行相關的檔案關閉的處理的。
5.IP地址歸屬地查詢
首先,尋找可查詢IP地址的介面,發現在www.ip138.com上有這個介面。通過測試,可發現ip地址查詢的介面(下圖下方的連結):類似於上一個例子,只要替換ipaddress這個關鍵詞就可以實現ip地址的查詢了。
下面是測試互動介面和對應程式碼:
注:這裡輸出respond物件的內容的時候,都是取r.text的一部分的內容的,而若直接輸出r.text的所有內容,可能會引起對應IDE的失效(或者 輸出負擔過大)。
而通過這個例子,也可以發現,對於一些可通過使用者輸入的資訊來進行相應的相應的響應的網站,都可以找到其對應的API,從而可用爬蟲程式進行自動的資訊填入和自動地根據資訊來進行相應的處理。比如,對於這一個例子,其API就是:
而這也是“以爬蟲視角看待網路內容”的表現方式之一。
程式碼:
# -*- coding:utf-8 -*-
import requests
def getHTMLText(url):
try:
kv = {'ip': '120.236.174.140'}
r = requests.get(url,params=kv)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.url)
return r.text
except:
print("Failed!")
url = "http://www.ip138.com/ips138.asp"
print(getHTMLText(url))
單元小結
pass