原文傳送門:http://blog.csdn.net/column/details/why-bug.htmlcss
[Python]網絡爬蟲(一):抓取網頁的含義和URL基本構成html
1、網絡爬蟲的定義node
網絡爬蟲,即Web Spider,是一個很形象的名字。python
把互聯網比喻成一個蜘蛛網,那麼Spider就是在網上爬來爬去的蜘蛛。
網絡蜘蛛是經過網頁的連接地址來尋找網頁的。git
從網站某一個頁面(一般是首頁)開始,讀取網頁的內容,找到在網頁中的其它連接地址,web
而後經過這些連接地址尋找下一個網頁,這樣一直循環下去,直到把這個網站全部的網頁都抓取完爲止。正則表達式
若是把整個互聯網當成一個網站,那麼網絡蜘蛛就能夠用這個原理把互聯網上全部的網頁都抓取下來。shell
這樣看來,網絡爬蟲就是一個爬行程序,一個抓取網頁的程序。編程
網絡爬蟲的基本操做是抓取網頁。json
那麼如何才能爲所欲爲地得到本身想要的頁面?
咱們先從URL開始。
2、瀏覽網頁的過程
抓取網頁的過程其實和讀者平時使用IE瀏覽器瀏覽網頁的道理是同樣的。
好比說你在瀏覽器的地址欄中輸入 www.baidu.com 這個地址。
打開網頁的過程其實就是瀏覽器做爲一個瀏覽的「客戶端」,向服務器端發送了 一次請求,把服務器端的文件「抓」到本地,再進行解釋、展示。
HTML是一種標記語言,用標籤標記內容並加以解析和區分。
3、URI和URL的概念和舉例
簡單的來說,URL就是在瀏覽器端輸入的 http://www.baidu.com 這個字符串。
在理解URL以前,首先要理解URI的概念。
什麼是URI?
Web上每種可用的資源,如 HTML文檔、圖像、視頻片斷、程序等都由一個通用資源標誌符(Universal Resource Identifier, URI)進行定位。
URI一般由三部分組成:
①訪問資源的命名機制;
②存放資源的主機名;
③資源自身 的名稱,由路徑表示。
以下面的URI:
http://www.why.com.cn/myhtml/html1223/
咱們能夠這樣解釋它:
①這是一個能夠經過HTTP協議訪問的資源,
②位於主機 www.webmonkey.com.cn上,
③經過路徑「/html/html40」訪問。
4、URL的理解和舉例
URL是URI的一個子集。它是Uniform Resource Locator的縮寫,譯爲「統一資源定位 符」。
通俗地說,URL是Internet上描述信息資源的字符串,主要用在各類WWW客戶程序和服務器程序上。
採用URL能夠用一種統一的格式來描述各類信息資源,包括文件、服務器的地址和目錄等。
URL的通常格式爲(帶方括號[]的爲可選項):
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
URL的格式由三部分組成:
①第一部分是協議(或稱爲服務方式)。
②第二部分是存有該資源的主機IP地址(有時也包括端口號)。
③第三部分是主機資源的具體地址,如目錄和文件名等。
第一部分和第二部分用「://」符號隔開,
第二部分和第三部分用「/」符號隔開。
第一部分和第二部分是不可缺乏的,第三部分有時能夠省略。
5、URL和URI簡單比較
URI屬於URL更低層次的抽象,一種字符串文本標準。
換句話說,URI屬於父類,而URL屬於URI的子類。URL是URI的一個子集。
URI的定義是:統一資源標識符;
URL的定義是:統一資源定位符。
兩者的區別在於,URI表示請求服務器的路徑,定義這麼一個資源。
而URL同時說明要如何訪問這個資源(http://)。
下面來看看兩個URL的小例子。
1.HTTP協議的URL示例:
使用超級文本傳輸協議HTTP,提供超級文本信息服務的資源。
例:http://www.peopledaily.com.cn/channel/welcome.htm
其計算機域名爲www.peopledaily.com.cn。
超級文本文件(文件類型爲.html)是在目錄 /channel下的welcome.htm。
這是中國人民日報的一臺計算機。
例:http://www.rol.cn.net/talk/talk1.htm
其計算機域名爲www.rol.cn.net。
超級文本文件(文件類型爲.html)是在目錄/talk下的talk1.htm。
這是瑞得聊天室的地址,可由此進入瑞得聊天室的第1室。
2.文件的URL
用URL表示文件時,服務器方式用file表示,後面要有主機IP地址、文件的存取路 徑(即目錄)和文件名等信息。
有時能夠省略目錄和文件名,但「/」符號不能省略。
例:file://ftp.yoyodyne.com/pub/files/foobar.txt
上面這個URL表明存放在主機ftp.yoyodyne.com上的pub/files/目錄下的一個文件,文件名是foobar.txt。
例:file://ftp.yoyodyne.com/pub
表明主機ftp.yoyodyne.com上的目錄/pub。
例:file://ftp.yoyodyne.com/
表明主機ftp.yoyodyne.com的根目錄。
爬蟲最主要的處理對象就是URL,它根據URL地址取得所須要的文件內容,而後對它 進行進一步的處理。
所以,準確地理解URL對理解網絡爬蟲相當重要。
[Python]網絡爬蟲(二):利用urllib2經過指定的URL抓取網頁內容
版本號:Python2.7.5,Python3改動較大,各位另尋教程。
所謂網頁抓取,就是把URL地址中指定的網絡資源從網絡流中讀取出來,保存到本地。
相似於使用程序模擬IE瀏覽器的功能,把URL做爲HTTP請求的內容發送到服務器端, 而後讀取服務器端的響應資源。
在Python中,咱們使用urllib2這個組件來抓取網頁。
urllib2是Python的一個獲取URLs(Uniform Resource Locators)的組件。
它以urlopen函數的形式提供了一個很是簡單的接口。
最簡單的urllib2的應用代碼只須要四行。
咱們新建一個文件urllib2_test01.py來感覺一下urllib2的做用:
咱們能夠打開百度主頁,右擊,選擇查看源代碼(火狐OR谷歌瀏覽器都可),會發現也是徹底同樣的內容。
也就是說,上面這四行代碼將咱們訪問百度時瀏覽器收到的代碼們所有打印了出來。
這就是一個最簡單的urllib2的例子。
除了"http:",URL一樣可使用"ftp:","file:"等等來替代。
HTTP是基於請求和應答機制的:
客戶端提出請求,服務端提供應答。
urllib2用一個Request對象來映射你提出的HTTP請求。
在它最簡單的使用形式中你將用你要請求的地址建立一個Request對象,
經過調用urlopen並傳入Request對象,將返回一個相關請求response對象,
這個應答對象如同一個文件對象,因此你能夠在Response中調用.read()。
咱們新建一個文件urllib2_test02.py來感覺一下:
urllib2使用相同的接口處理全部的URL頭。例如你能夠像下面那樣建立一個ftp請求。
1.發送data表單數據
這個內容相信作過Web端的都不會陌生,
有時候你但願發送一些數據到URL(一般URL與CGI[通用網關接口]腳本,或其餘WEB應用程序掛接)。
在HTTP中,這個常用熟知的POST請求發送。
這個一般在你提交一個HTML表單時由你的瀏覽器來作。
並非全部的POSTs都來源於表單,你可以使用POST提交任意的數據到你本身的程序。
通常的HTML表單,data須要編碼成標準形式。而後作爲data參數傳到Request對象。
編碼工做使用urllib的函數而非urllib2。
咱們新建一個文件urllib2_test03.py來感覺一下:
GET和POST請求的不一樣之處是POST請求一般有"反作用",
它們會因爲某種途徑改變系統狀態(例如提交成堆垃圾到你的門口)。
Data一樣能夠經過在Get請求的URL自己上面編碼來傳送。
2.設置Headers到http請求
有一些站點不喜歡被程序(非人爲訪問)訪問,或者發送不一樣版本的內容到不一樣的瀏覽器。
默認的urllib2把本身做爲「Python-urllib/x.y」(x和y是Python主版本和次版本號,例如Python-urllib/2.7),
這個身份可能會讓站點迷惑,或者乾脆不工做。
瀏覽器確認本身身份是經過User-Agent頭,當你建立了一個請求對象,你能夠給他一個包含頭數據的字典。
下面的例子發送跟上面同樣的內容,但把自身模擬成Internet Explorer。
(多謝你們的提醒,如今這個Demo已經不可用了,不過原理仍是那樣的)。
先來講一說HTTP的異常處理問題。
當urlopen不可以處理一個response時,產生urlError。
不過一般的Python APIs異常如ValueError,TypeError等也會同時產生。
HTTPError是urlError的子類,一般在特定HTTP URLs中產生。
1.URLError
一般,URLError在沒有網絡鏈接(沒有路由到特定服務器),或者服務器不存在的狀況下產生。
這種狀況下,異常一樣會帶有"reason"屬性,它是一個tuple(能夠理解爲不可變的數組),
包含了一個錯誤號和一個錯誤信息。
咱們建一個urllib2_test06.py來感覺一下異常的處理:
按下F5,能夠看到打印出來的內容是:
[Errno 11001] getaddrinfo failed
也就是說,錯誤號是11001,內容是getaddrinfo failed
2.HTTPError
服務器上每個HTTP 應答對象response包含一個數字"狀態碼"。
有時狀態碼指出服務器沒法完成請求。默認的處理器會爲你處理一部分這種應答。
例如:假如response是一個"重定向",須要客戶端從別的地址獲取文檔,urllib2將爲你處理。
其餘不能處理的,urlopen會產生一個HTTPError。
典型的錯誤包含"404"(頁面沒法找到),"403"(請求禁止),和"401"(帶驗證請求)。
HTTP狀態碼錶示HTTP協議所返回的響應的狀態。
好比客戶端向服務器發送請求,若是成功地得到請求的資源,則返回的狀態碼爲200,表示響應成功。
若是請求的資源不存在, 則一般返回404錯誤。
HTTP狀態碼一般分爲5種類型,分別以1~5五個數字開頭,由3位整數組成:
------------------------------------------------------------------------------------------------
200:請求成功 處理方式:得到響應的內容,進行處理
201:請求完成,結果是建立了新資源。新建立資源的URI可在響應的實體中獲得 處理方式:爬蟲中不會遇到
202:請求被接受,但處理還沒有完成 處理方式:阻塞等待
204:服務器端已經實現了請求,可是沒有返回新的信 息。若是客戶是用戶代理,則無須爲此更新自身的文檔視圖。 處理方式:丟棄
300:該狀態碼不被HTTP/1.0的應用程序直接使用, 只是做爲3XX類型迴應的默認解釋。存在多個可用的被請求資源。 處理方式:若程序中可以處理,則進行進一步處理,若是程序中不能處理,則丟棄
301:請求到的資源都會分配一個永久的URL,這樣就能夠在未來經過該URL來訪問此資源 處理方式:重定向到分配的URL
302:請求到的資源在一個不一樣的URL處臨時保存 處理方式:重定向到臨時的URL
304 請求的資源未更新 處理方式:丟棄
400 非法請求 處理方式:丟棄
401 未受權 處理方式:丟棄
403 禁止 處理方式:丟棄
404 沒有找到 處理方式:丟棄
5XX 迴應代碼以「5」開頭的狀態碼錶示服務器端發現本身出現錯誤,不能繼續執行請求 處理方式:丟棄
------------------------------------------------------------------------------------------------
Error Codes錯誤碼
由於默認的處理器處理了重定向(300之外號碼),而且100-299範圍的號碼指示成功,因此你只能看到400-599的錯誤號碼。
BaseHTTPServer.BaseHTTPRequestHandler.response是一個頗有用的應答號碼字典,顯示了HTTP協議使用的全部的應答號。
當一個錯誤號產生後,服務器返回一個HTTP錯誤號,和一個錯誤頁面。
你可使用HTTPError實例做爲頁面返回的應答對象response。
這表示和錯誤屬性同樣,它一樣包含了read,geturl,和info方法。
咱們建一個urllib2_test07.py來感覺一下:
3.Wrapping
因此若是你想爲HTTPError或URLError作準備,將有兩個基本的辦法。推薦使用第二種。
咱們建一個urllib2_test08.py來示範一下第一種異常處理的方案:
咱們建一個urllib2_test09.py來示範一下第二種異常處理的方案:
在開始後面的內容以前,先來解釋一下urllib2中的兩個個方法:info and geturl
urlopen返回的應答對象response(或者HTTPError實例)有兩個頗有用的方法info()和geturl()1.geturl():
這個返回獲取的真實的URL,這個頗有用,由於urlopen(或者opener對象使用的)或許會有重定向。獲取的URL或許跟請求URL不一樣。
以人人中的一個超級連接爲例,
咱們建一個urllib2_test10.py來比較一下原始URL和重定向的連接:
2.info():
這個返回對象的字典對象,該字典描述了獲取的頁面狀況。一般是服務器發送的特定頭headers。目前是httplib.HTTPMessage 實例。
經典的headers包含"Content-length","Content-type",和其餘內容。
咱們建一個urllib2_test11.py來測試一下info的應用:
下面來講一說urllib2中的兩個重要概念:Openers和Handlers。
1.Openers:
當你獲取一個URL你使用一個opener(一個urllib2.OpenerDirector的實例)。
正常狀況下,咱們使用默認opener:經過urlopen。
但你可以建立個性的openers。
2.Handles:
Openers使用處理器handlers,全部的「繁重」工做由handlers處理。
每一個handlers知道如何經過特定協議打開URLs,或者如何處理URL打開時的各個方面。
例如HTTP重定向或者HTTP cookies。
若是你但願用特定處理器獲取URLs你會想建立一個openers,例如獲取一個能處理cookie的opener,或者獲取一個不重定向的opener。
要建立一個 opener,能夠實例化一個OpenerDirector,
而後調用.add_handler(some_handler_instance)。
一樣,可使用build_opener,這是一個更加方便的函數,用來建立opener對象,他只須要一次函數調用。其餘的處理器handlers你或許會但願處理代理,驗證,和其餘經常使用但有點特殊的狀況。
Opener對象有一個open方法。
該方法能夠像urlopen函數那樣直接用來獲取urls:一般沒必要調用install_opener,除了爲了方便。
說完了上面兩個內容,下面咱們來看一下基本認證的內容,這裏會用到上面說起的Opener和Handler。
Basic Authentication 基本驗證爲了展現建立和安裝一個handler,咱們將使用HTTPBasicAuthHandler。
當須要基礎驗證時,服務器發送一個header(401錯誤碼) 請求驗證。這個指定了scheme 和一個‘realm’,看起來像這樣:Www-authenticate: SCHEME realm="REALM".
例如客戶端必須使用新的請求,並在請求頭裏包含正確的姓名和密碼。
這是「基礎驗證」,爲了簡化這個過程,咱們能夠建立一個HTTPBasicAuthHandler的實例,並讓opener使用這個handler就能夠啦。
HTTPBasicAuthHandler使用一個密碼管理的對象來處理URLs和realms來映射用戶名和密碼。
若是你知道realm(從服務器發送來的頭裏)是什麼,你就能使用HTTPPasswordMgr。
一般人們不關心realm是什麼。那樣的話,就能用方便的HTTPPasswordMgrWithDefaultRealm。
這個將在你爲URL指定一個默認的用戶名和密碼。
這將在你爲特定realm提供一個其餘組合時獲得提供。
咱們經過給realm參數指定None提供給add_password來指示這種狀況。
最高層次的URL是第一個要求驗證的URL。你傳給.add_password()更深層次的URLs將一樣合適。
說了這麼多廢話,下面來用一個例子演示一下上面說到的內容。
咱們建一個urllib2_test12.py來測試一下info的應用:
注意:以上的例子咱們僅僅提供咱們的HHTPBasicAuthHandler給build_opener。
默認的openers有正常情況的handlers:ProxyHandler,UnknownHandler,HTTPHandler,HTTPDefaultErrorHandler, HTTPRedirectHandler,FTPHandler, FileHandler, HTTPErrorProcessor。
代碼中的top_level_url 實際上能夠是完整URL(包含"http:",以及主機名及可選的端口號)。
例如:http://example.com/。
也能夠是一個「authority」(即主機名和可選的包含端口號)。
例如:「example.com」 or 「example.com:8080」。
後者包含了端口號。
[Python]網絡爬蟲(五):urllib2的使用細節與抓站技巧
前面說到了urllib2的簡單入門,下面整理了一部分urllib2的使用細節。
1.Proxy 的設置
urllib2 默認會使用環境變量 http_proxy 來設置 HTTP Proxy。
若是想在程序中明確控制 Proxy 而不受環境變量的影響,可使用代理。
新建test14來實現一個簡單的代理Demo:
這裏要注意的一個細節,使用 urllib2.install_opener() 會設置 urllib2 的全局 opener 。
這樣後面的使用會很方便,但不能作更細緻的控制,好比想在程序中使用兩個不一樣的 Proxy 設置等。
比較好的作法是不使用 install_opener 去更改全局的設置,而只是直接調用 opener 的 open 方法代替全局的 urlopen 方法。
3.在 HTTP Request 中加入特定的 Header
要加入 header,須要使用 Request 對象:
5.Cookie
urllib2 對 Cookie 的處理也是自動的。若是須要獲得某個 Cookie 項的值,能夠這麼作:運行以後就會輸出訪問百度的Cookie值:
6.使用 HTTP 的 PUT 和 DELETE 方法
urllib2 只支持 HTTP 的 GET 和 POST 方法,若是要使用 HTTP PUT 和 DELETE ,只能使用比較低層的 httplib 庫。雖然如此,咱們仍是能經過下面的方式,使 urllib2 可以發出 PUT 或DELETE 的請求:
7.獲得 HTTP 的返回碼
對於 200 OK 來講,只要使用 urlopen 返回的 response 對象的 getcode() 方法就能夠獲得 HTTP 的返回碼。但對其它返回碼來講,urlopen 會拋出異常。這時候,就要檢查異常對象的 code 屬性了:8.Debug Log
使用 urllib2 時,能夠經過下面的方法把 debug Log 打開,這樣收發包的內容就會在屏幕上打印出來,方便調試,有時能夠省去抓包的工做這樣就能夠看到傳輸的數據包內容了:
9.表單的處理
登陸必要填表,表單怎麼填?
首先利用工具截取所要填表的內容。
好比我通常用firefox+httpfox插件來看看本身到底發送了些什麼包。
以verycd爲例,先找到本身發的POST請求,以及POST表單項。
能夠看到verycd的話須要填username,password,continueURI,fk,login_submit這幾項,其中fk是隨機生成的(其實不太隨機,看上去像是把epoch時間通過簡單的編碼生成的),須要從網頁獲取,也就是說得先訪問一次網頁,用正則表達式等工具截取返回數據中的fk項。continueURI顧名思義能夠隨便寫,login_submit是固定的,這從源碼能夠看出。還有username,password那就很顯然了:
10.假裝成瀏覽器訪問
某些網站反感爬蟲的到訪,因而對爬蟲一概拒絕請求
這時候咱們須要假裝成瀏覽器,這能夠經過修改http包中的header來實現
就是檢查你發送請求的header裏面,referer站點是否是他本身,
因此咱們只須要像把headers的referer改爲該網站便可,以cnbeta爲例:
#... headers = { 'Referer':'http://www.cnbeta.com/articles' } #...
headers是一個dict數據結構,你能夠放入任何想要的header,來作一些假裝。
例如,有些網站喜歡讀取header中的X-Forwarded-For來看看人家的真實IP,能夠直接把X-Forwarde-For改了。
接下來準備用糗百作一個爬蟲的小例子。
可是在這以前,先詳細的整理一下Python中的正則表達式的相關內容。
正則表達式在Python爬蟲中的做用就像是老師點名時用的花名冊同樣,是必不可少的神兵利器。
如下內容轉自CNBLOG:http://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html
整理時沒有注意,實在抱歉。
1、 正則表達式基礎
1.1.概念介紹正則表達式是用於處理字符串的強大工具,它並非Python的一部分。
其餘編程語言中也有正則表達式的概念,區別只在於不一樣的編程語言實現支持的語法數量不一樣。
它擁有本身獨特的語法以及一個獨立的處理引擎,在提供了正則表達式的語言裏,正則表達式的語法都是同樣的。
下圖展現了使用正則表達式進行匹配的流程:
正則表達式的大體匹配過程是:
1.依次拿出表達式和文本中的字符比較,
2.若是每個字符都能匹配,則匹配成功;一旦有匹配不成功的字符則匹配失敗。
3.若是表達式中有量詞或邊界,這個過程會稍微有一些不一樣。
下圖列出了Python支持的正則表達式元字符和語法:
正則表達式一般用於在文本中查找匹配的字符串。
貪婪模式,老是嘗試匹配儘量多的字符;
非貪婪模式則相反,老是嘗試匹配儘量少的字符。
Python裏數量詞默認是貪婪的。
例如:正則表達式"ab*"若是用於查找"abbbc",將找到"abbb"。
而若是使用非貪婪的數量詞"ab*?",將找到"a"。
與大多數編程語言相同,正則表達式裏使用"\"做爲轉義字符,這就可能形成反斜槓困擾。
假如你須要匹配文本中的字符"\",那麼使用編程語言表示的正則表達式裏將須要4個反斜槓"\\\\":
第一個和第三個用於在編程語言裏將第二個和第四個轉義成反斜槓,
轉換成兩個反斜槓\\後再在正則表達式裏轉義成一個反斜槓用來匹配反斜槓\。
這樣顯然是很是麻煩的。
Python裏的原生字符串很好地解決了這個問題,這個例子中的正則表達式可使用r"\\"表示。
一樣,匹配一個數字的"\\d"能夠寫成r"\d"。
有了原生字符串,媽媽不再用擔憂個人反斜槓問題~
Python經過re模塊提供對正則表達式的支持。
使用re的通常步驟是:
Step1:先將正則表達式的字符串形式編譯爲Pattern實例。
Step2:而後使用Pattern實例處理文本並得到匹配結果(一個Match實例)。
Step3:最後使用Match實例得到信息,進行其餘的操做。
咱們新建一個re01.py來試驗一下re的應用:
下面來具體看看代碼中的關鍵方法。
★ re.compile(strPattern[, flag]):
這個方法是Pattern類的工廠方法,用於將字符串形式的正則表達式編譯爲Pattern對象。
第二個參數flag是匹配模式,取值可使用按位或運算符'|'表示同時生效,好比re.I | re.M。
另外,你也能夠在regex字符串中指定模式,
好比re.compile('pattern', re.I | re.M)與re.compile('(?im)pattern')是等價的。
可選值有:
如下兩個正則表達式是等價的:
這些方法可使用Pattern實例的相應方法替代,惟一的好處是少寫一行re.compile()代碼,
但同時也沒法複用編譯後的Pattern對象。
這些方法將在Pattern類的實例方法部分一塊兒介紹。
如一開始的hello實例能夠簡寫爲:
2.2. Match
Match對象是一次匹配的結果,包含了不少關於這次匹配的信息,可使用Match提供的可讀屬性或方法來獲取這些信息。
屬性:
方法:
Pattern對象是一個編譯好的正則表達式,經過Pattern提供的一系列方法能夠對文本進行匹配查找。
Pattern不能直接實例化,必須使用re.compile()進行構造,也就是re.compile()返回的對象。
Pattern提供了幾個可讀屬性用於獲取表達式的相關信息:
1.match
match(string[, pos[, endpos]]) | re.match(pattern, string[, flags]):
這個方法將從string的pos下標處起嘗試匹配pattern;
若是pattern結束時仍可匹配,則返回一個Match對象;
若是匹配過程當中pattern沒法匹配,或者匹配未結束就已到達endpos,則返回None。
pos和endpos的默認值分別爲0和len(string);
re.match()沒法指定這兩個參數,參數flags用於編譯pattern時指定匹配模式。
注意:這個方法並非徹底匹配。
當pattern結束時若string還有剩餘字符,仍然視爲成功。
想要徹底匹配,能夠在表達式末尾加上邊界匹配符'$'。
下面來看一個Match的簡單案例:
2.search
search(string[, pos[, endpos]]) | re.search(pattern, string[, flags]):
這個方法用於查找字符串中能夠匹配成功的子串。
從string的pos下標處起嘗試匹配pattern,
若是pattern結束時仍可匹配,則返回一個Match對象;
若沒法匹配,則將pos加1後從新嘗試匹配;
直到pos=endpos時仍沒法匹配則返回None。
pos和endpos的默認值分別爲0和len(string));
re.search()沒法指定這兩個參數,參數flags用於編譯pattern時指定匹配模式。
那麼它和match有什麼區別呢?
match()函數只檢測re是否是在string的開始位置匹配,
search()會掃描整個string查找匹配,
match()只有在0位置匹配成功的話纔有返回,若是不是開始位置匹配成功的話,match()就返回none
例如:
print(re.match(‘super’, ‘superstition’).span())
會返回(0, 5)
print(re.match(‘super’, ‘insuperable’))
則返回None
search()會掃描整個字符串並返回第一個成功的匹配
例如:
print(re.search(‘super’, ‘superstition’).span())
返回(0, 5)
print(re.search(‘super’, ‘insuperable’).span())
返回(2, 7)
看一個search的實例:
3.split
split(string[, maxsplit]) | re.split(pattern, string[, maxsplit]):
按照可以匹配的子串將string分割後返回列表。
maxsplit用於指定最大分割次數,不指定將所有分割。
4.findall
findall(string[, pos[, endpos]]) | re.findall(pattern, string[, flags]):
搜索string,以列表形式返回所有能匹配的子串。
5.finditer
finditer(string[, pos[, endpos]]) | re.finditer(pattern, string[, flags]):
搜索string,返回一個順序訪問每個匹配結果(Match對象)的迭代器。
6.sub
sub(repl, string[, count]) | re.sub(pattern, repl, string[, count]):
使用repl替換string中每個匹配的子串後返回替換後的字符串。
當repl是一個字符串時,可使用\id或\g<id>、\g<name>引用分組,但不能使用編號0。
當repl是一個方法時,這個方法應當只接受一個參數(Match對象),並返回一個字符串用於替換(返回的字符串中不能再引用分組)。
count用於指定最多替換次數,不指定時所有替換。
subn(repl, string[, count]) |re.sub(pattern, repl, string[, count]):
返回 (sub(repl, string[, count]), 替換次數)。
[Python]網絡爬蟲(八):糗事百科的網絡爬蟲(v0.3)源碼及解析(簡化更新)
Q&A:
1.爲何有段時間顯示糗事百科不可用?
答:前段時間由於糗事百科添加了Header的檢驗,致使沒法爬取,須要在代碼中模擬Header。如今代碼已經做了修改,能夠正常使用。
2.爲何須要單獨新建個線程?
答:基本流程是這樣的:爬蟲在後臺新起一個線程,一直爬取兩頁的糗事百科,若是剩餘不足兩頁,則再爬一頁。用戶按下回車只是從庫存中獲取最新的內容,而不是上網獲取,因此瀏覽更順暢。也能夠把加載放在主線程,不過這樣會致使爬取過程當中等待時間過長的問題。
項目內容:
用Python寫的糗事百科的網絡爬蟲。
使用方法:
新建一個Bug.py文件,而後將代碼複製到裏面後,雙擊運行。
程序功能:
在命令提示行中瀏覽糗事百科。
原理解釋:
首先,先瀏覽一下糗事百科的主頁:http://www.qiushibaike.com/hot/page/1
能夠看出來,連接中page/後面的數字就是對應的頁碼,記住這一點爲之後的編寫作準備。
而後,右擊查看頁面源碼:
觀察發現,每個段子都用div標記,其中class必爲content,title是發帖時間,咱們只須要用正則表達式將其「扣」出來就能夠了。
明白了原理以後,剩下的就是正則表達式的內容了,能夠參照這篇博文:
http://blog.csdn.net/wxg694175346/article/details/8929576
運行效果:
百度貼吧的爬蟲製做和糗百的爬蟲製做原理基本相同,都是經過查看源碼扣出關鍵數據,而後將其存儲到本地txt文件。
源碼下載:
http://download.csdn.net/detail/wxg694175346/6925583
用Python寫的百度貼吧的網絡爬蟲。
使用方法:
新建一個BugBaidu.py文件,而後將代碼複製到裏面後,雙擊運行。
程序功能:
將貼吧中樓主發佈的內容打包txt存儲到本地。
原理解釋:
首先,先瀏覽一下某一條貼吧,點擊只看樓主並點擊第二頁以後url發生了一點變化,變成了:
http://tieba.baidu.com/p/2296712428?see_lz=1&pn=1
能夠看出來,see_lz=1是隻看樓主,pn=1是對應的頁碼,記住這一點爲之後的編寫作準備。
這就是咱們須要利用的url。接下來就是查看頁面源碼。
首先把題目摳出來存儲文件的時候會用到。
能夠看到百度使用gbk編碼,標題使用h1標記:
一樣,正文部分用div和class綜合標記,接下來要作的只是用正則表達式來匹配便可。
運行截圖:
生成的txt文件:
先來講一下咱們學校的網站:
http://jwxt.sdu.edu.cn:7777/zhxt_bks/zhxt_bks.html
查詢成績須要登陸,而後顯示各學科成績,可是隻顯示成績而沒有績點,也就是加權平均分。
顯然這樣手動計算績點是一件很是麻煩的事情。因此咱們能夠用python作一個爬蟲來解決這個問題。
1.決戰前夜
先來準備一下工具:HttpFox插件。
這是一款http協議分析插件,分析頁面請求和響應的時間、內容、以及瀏覽器用到的COOKIE等。
以我爲例,安裝在火狐上便可,效果如圖:
能夠很是直觀的查看相應的信息。
點擊start是開始檢測,點擊stop暫停檢測,點擊clear清除內容。
通常在使用以前,點擊stop暫停,而後點擊clear清屏,確保看到的是訪問當前頁面得到的數據。
2.深刻敵後
下面就去山東大學的成績查詢網站,看一看在登陸的時候,到底發送了那些信息。
先來到登陸頁面,把httpfox打開,clear以後,點擊start開啓檢測:
輸入完了我的信息,確保httpfox處於開啓狀態,而後點擊肯定提交信息,實現登陸。
這個時候能夠看到,httpfox檢測到了三條信息:
這時點擊stop鍵,確保捕獲到的是訪問該頁面以後反饋的數據,以便咱們作爬蟲的時候模擬登錄使用。
3.庖丁解牛
乍一看咱們拿到了三個數據,兩個是GET的一個是POST的,可是它們究竟是什麼,應該怎麼用,咱們還一無所知。
因此,咱們須要挨個查看一下捕獲到的內容。
先看POST的信息:
既然是POST的信息,咱們就直接看PostData便可。
能夠看到一共POST兩個數據,stuid和pwd。
而且從Type的Redirect to能夠看出,POST完畢以後跳轉到了bks_login2.loginmessage頁面。
由此看出,這個數據是點擊肯定以後提交的表單數據。
點擊cookie標籤,看看cookie信息:
沒錯,收到了一個ACCOUNT的cookie,而且在session結束以後自動銷燬。
那麼提交以後收到了哪些信息呢?
咱們來看看後面的兩個GET數據。
先看第一個,咱們點擊content標籤能夠查看收到的內容,是否是有一種生吞活剝的快感-。-HTML源碼暴露無疑了:
看來這個只是顯示頁面的html源碼而已,點擊cookie,查看cookie的相關信息:
啊哈,原來html頁面的內容是發送了cookie信息以後才接受到的。
再來看看最後一個接收到的信息:
大體看了一下應該只是一個叫作style.css的css文件,對咱們沒有太大的做用。
4.冷靜應戰
既然已經知道了咱們向服務器發送了什麼數據,也知道了咱們接收到了什麼數據,基本的流程以下:
OK,看上去好像很簡單的樣紙。那下面咱們就來試試看吧。
可是在實驗以前,還有一個問題沒有解決,就是POST的數據到底發送到了哪裏?
再來看一下當初的頁面:
很明顯是用一個html框架來實現的,也就是說,咱們在地址欄看到的地址並非右邊提交表單的地址。
那麼怎樣才能得到真正的地址-。-右擊查看頁面源代碼:
嗯沒錯,那個name="w_right"的就是咱們要的登陸頁面。
網站的原來的地址是:
http://jwxt.sdu.edu.cn:7777/zhxt_bks/zhxt_bks.html
因此,真正的表單提交的地址應該是:
http://jwxt.sdu.edu.cn:7777/zhxt_bks/xk_login.html
輸入一看,果不其然:
靠竟然是清華大學的選課系統。。。目測是我校懶得作頁面了就直接借了。。結果連標題都不改一下。。。
可是這個頁面依舊不是咱們須要的頁面,由於咱們的POST數據提交到的頁面,應該是表單form的ACTION中提交到的頁面。
也就是說,咱們須要查看源碼,來知道POST數據到底發送到了哪裏:
嗯,目測這個纔是提交POST數據的地址。
整理到地址欄中,完整的地址應該以下:
http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login
(獲取的方式很簡單,在火狐瀏覽器中直接點擊那個連接就能看到這個連接的地址了)
5.小試牛刀
接下來的任務就是:用python模擬發送一個POST的數據並取到返回的cookie值。
關於cookie的操做能夠看看這篇博文:
http://blog.csdn.net/wxg694175346/article/details/8925978
咱們先準備一個POST的數據,再準備一個cookie的接收,而後寫出源碼以下:
ok,如此這般,咱們就算模擬登錄成功了。
6.偷天換日
接下來的任務就是用爬蟲獲取到學生的成績。
再來看看源網站。
開啓HTTPFOX以後,點擊查當作績,發現捕獲到了以下的數據:
點擊第一個GET的數據,查看內容能夠發現Content就是獲取到的成績的內容。
而獲取到的頁面連接,從頁面源代碼中右擊查看元素,能夠看到點擊連接以後跳轉的頁面(火狐瀏覽器只須要右擊,「查看此框架」,便可):
從而能夠獲得查當作績的連接以下:
http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre
7.萬事俱備
如今萬事俱備啦,因此只須要把連接應用到爬蟲裏面,看看可否查看到成績的頁面。
從httpfox能夠看到,咱們發送了一個cookie才能返回成績的信息,因此咱們就用python模擬一個cookie的發送,以此來請求成績的信息:
既然這樣就沒有什麼問題了吧,用正則表達式將數據稍稍處理一下,取出學分和相應的分數就能夠了。
8.手到擒來
這麼一大堆html源碼顯然是不利於咱們處理的,下面要用正則表達式來摳出必須的數據。
關於正則表達式的教程能夠看看這個博文:
http://blog.csdn.net/wxg694175346/article/details/8929576
咱們來看當作績的源碼:
既然如此,用正則表達式就易如反掌了。
咱們將代碼稍稍整理一下,而後用正則來取出數據:
ok,接下來的只是數據的處理問題了。。
9.凱旋而歸
完整的代碼以下,至此一個完整的爬蟲項目便完工了。
[Python]網絡爬蟲(11):亮劍!爬蟲框架小抓抓Scrapy閃亮登場!
前面十章爬蟲筆記陸陸續續記錄了一些簡單的Python爬蟲知識,
用來解決簡單的貼吧下載,績點運算天然不在話下。
不過要想批量下載大量的內容,好比知乎的全部的問答,那便顯得遊刃不有餘了點。
因而乎,爬蟲框架Scrapy就這樣出場了!
Scrapy = Scrach+Python,Scrach這個單詞是抓取的意思,
暫且能夠叫它:小抓抓吧。
小抓抓的官網地址:點我點我。
那麼下面來簡單的演示一下小抓抓Scrapy的安裝流程。
具體流程參照:官網教程
友情提醒:必定要按照Python的版本下載,要否則安裝的時候會提醒找不到Python。建議你們安裝32位是由於有些版本的必備軟件64位很差找。
1.安裝Python(建議32位)
建議安裝Python2.7.x,3.x貌似還不支持。
安裝完了記得配置環境,將python目錄和python目錄下的Scripts目錄添加到系統環境變量的Path裏。
在cmd中輸入python若是出現版本信息說明配置完畢。
2.安裝lxml
lxml是一種使用 Python 編寫的庫,能夠迅速、靈活地處理 XML。點擊這裏選擇對應的Python版本安裝。
3.安裝setuptools
用來安裝egg文件,點擊這裏下載python2.7的對應版本的setuptools。
4.安裝zope.interface
可使用第三步下載的setuptools來安裝egg文件,如今也有exe版本,點擊這裏下載。
5.安裝Twisted
Twisted是用Python實現的基於事件驅動的網絡引擎框架,點擊這裏下載。
6.安裝pyOpenSSL
pyOpenSSL是Python的OpenSSL接口,點擊這裏下載。
7.安裝win32py
提供win32api,點擊這裏下載
8.安裝Scrapy
終於到了激動人心的時候了!安裝了那麼多小部件以後終於輪到主角登場。
直接在cmd中輸入easy_install scrapy回車便可。
9.檢查安裝
打開一個cmd窗口,在任意位置執行scrapy命令,獲得下列頁面,表示環境配置成功。
[Python]網絡爬蟲(12):爬蟲框架Scrapy的第一個爬蟲示例入門教程
(建議你們多看看官網教程:教程地址)
咱們使用dmoz.org這個網站來做爲小抓抓一展身手的對象。
首先先要回答一個問題。
問:把網站裝進爬蟲裏,總共分幾步?
答案很簡單,四步:
好的,基本流程既然肯定了,那接下來就一步一步的完成就能夠了。
1.新建項目(Project)
在空目錄下按住Shift鍵右擊,選擇「在此處打開命令窗口」,輸入一下命令:
能夠看到將會建立一個tutorial文件夾,目錄結構以下:
下面來簡單介紹一下各個文件的做用:
2.明確目標(Item)
在Scrapy中,items是用來加載抓取內容的容器,有點像Python中的Dic,也就是字典,可是提供了一些額外的保護減小錯誤。
通常來講,item能夠用scrapy.item.Item類來建立,而且用scrapy.item.Field對象來定義屬性(能夠理解成相似於ORM的映射關係)。
接下來,咱們開始來構建item模型(model)。
首先,咱們想要的內容有:
修改tutorial目錄下的items.py文件,在本來的class後面添加咱們本身的class。
由於要抓dmoz.org網站的內容,因此咱們能夠將其命名爲DmozItem:
剛開始看起來可能會有些看不懂,可是定義這些item能讓你用其餘組件的時候知道你的 items究竟是什麼。
能夠把Item簡單的理解成封裝好的類對象。
3.製做爬蟲(Spider)
製做爬蟲,整體分兩步:先爬再取。
也就是說,首先你要獲取整個網頁的全部內容,而後再取出其中對你有用的部分。
3.1爬
Spider是用戶本身編寫的類,用來從一個域(或域組)中抓取信息。
他們定義了用於下載的URL列表、跟蹤連接的方案、解析網頁內容的方式,以此來提取items。
要創建一個Spider,你必須用scrapy.spider.BaseSpider建立一個子類,並肯定三個強制的屬性:
這裏能夠參考寬度爬蟲教程中說起的思想來幫助理解,教程傳送:[Java] 知乎下巴第5集:使用HttpClient工具包和寬度爬蟲。
也就是把Url存儲下來並依此爲起點逐步擴散開去,抓取全部符合條件的網頁Url存儲起來繼續爬取。
下面咱們來寫第一隻爬蟲,命名爲dmoz_spider.py,保存在tutorial\spiders目錄下。
dmoz_spider.py代碼以下:
從parse函數能夠看出,將連接的最後兩個地址取出做爲文件名進行存儲。
而後運行一下看看,在tutorial目錄下按住shift右擊,在此處打開命令窗口,輸入:
報錯了:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xb0 in position 1: ordinal not in range(128)
運行第一個Scrapy項目就報錯,真是命運多舛。
應該是出了編碼問題,谷歌了一下找到了解決方案:
在python的Lib\site-packages文件夾下新建一個sitecustomize.py:
再次運行,OK,問題解決了,看一下結果:
最後一句INFO: Closing spider (finished)代表爬蟲已經成功運行而且自行關閉了。
包含 [dmoz]的行 ,那對應着咱們的爬蟲運行的結果。
能夠看到start_urls中定義的每一個URL都有日誌行。
還記得咱們的start_urls嗎?
http://www.dmoz.org/Computers/Programming/Languages/Python/Books
http://www.dmoz.org/Computers/Programming/Languages/Python/Resources
由於這些URL是起始頁面,因此他們沒有引用(referrers),因此在它們的每行末尾你會看到 (referer: <None>)。
在parse 方法的做用下,兩個文件被建立:分別是 Books 和 Resources,這兩個文件中有URL的頁面內容。
那麼在剛剛的電閃雷鳴之中到底發生了什麼呢?
首先,Scrapy爲爬蟲的 start_urls屬性中的每一個URL建立了一個 scrapy.http.Request 對象 ,並將爬蟲的parse 方法指定爲回調函數。
而後,這些 Request被調度並執行,以後經過parse()方法返回scrapy.http.Response對象,並反饋給爬蟲。
3.2取
爬取整個網頁完畢,接下來的就是的取過程了。
光存儲一整個網頁仍是不夠用的。
在基礎的爬蟲裏,這一步能夠用正則表達式來抓。
在Scrapy裏,使用一種叫作 XPath selectors的機制,它基於 XPath表達式。
若是你想了解更多selectors和其餘機制你能夠查閱資料:點我點我
這是一些XPath表達式的例子和他們的含義
以上只是幾個使用XPath的簡單例子,可是實際上XPath很是強大。
能夠參照W3C教程:點我點我。
必須經過一個 Response 對象對他們進行實例化操做。
你會發現Selector對象展現了文檔的節點結構。所以,第一個實例化的selector必與根節點或者是整個目錄有關 。
在Scrapy裏面,Selectors 有四種基礎的方法(點擊查看API文檔):
3.3xpath實驗
下面咱們在Shell裏面嘗試一下Selector的用法。
實驗的網址:http://www.dmoz.org/Computers/Programming/Languages/Python/Books/
熟悉完了實驗的小白鼠,接下來就是用Shell爬取網頁了。
進入到項目的頂層目錄,也就是第一層tutorial文件夾下,在cmd中輸入:
在Shell載入後,你將得到response迴應,存儲在本地變量 response中。
因此若是你輸入response.body,你將會看到response的body部分,也就是抓取到的頁面內容:
或者輸入response.headers 來查看它的 header部分:
如今就像是一大堆沙子握在手裏,裏面藏着咱們想要的金子,因此下一步,就是用篩子搖兩下,把雜質出去,選出關鍵的內容。
selector就是這樣一個篩子。
在舊的版本中,Shell實例化兩種selectors,一個是解析HTML的 hxs 變量,一個是解析XML 的 xxs 變量。
而如今的Shell爲咱們準備好的selector對象,sel,能夠根據返回的數據類型自動選擇最佳的解析方案(XML or HTML)。
而後咱們來搗弄一下!~
要完全搞清楚這個問題,首先先要知道,抓到的頁面究竟是個什麼樣子。
好比,咱們要抓取網頁的標題,也就是<title>這個標籤:
能夠輸入:
這樣就能把這個標籤取出來了,用extract()和text()還能夠進一步作處理。
備註:簡單的羅列一下有用的xpath路徑表達式:
表達式 | 描述 |
---|---|
nodename | 選取此節點的全部子節點。 |
/ | 從根節點選取。 |
// | 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置。 |
. | 選取當前節點。 |
.. | 選取當前節點的父節點。 |
@ | 選取屬性。 |
所有的實驗結果以下,In[i]表示第i次實驗的輸入,Out[i]表示第i次結果的輸出(建議你們參照:W3C教程):
固然title這個標籤對咱們來講沒有太多的價值,下面咱們就來真正抓取一些有意義的東西。
使用火狐的審查元素咱們能夠清楚地看到,咱們須要的東西以下:
咱們能夠用以下代碼來抓取這個<li>標籤:
從<li>標籤中,能夠這樣獲取網站的描述:
能夠這樣獲取網站的標題:
能夠這樣獲取網站的超連接:
固然,前面的這些例子是直接獲取屬性的方法。
咱們注意到xpath返回了一個對象列表,
那麼咱們也能夠直接調用這個列表中對象的屬性挖掘更深的節點
(參考:Nesting selectors andWorking with relative XPaths in the Selectors):
sites = sel.xpath('//ul/li')
for site in sites:
title = site.xpath('a/text()').extract()
link = site.xpath('a/@href').extract()
desc = site.xpath('text()').extract()
print title, link, desc
3.4xpath實戰
咱們用shell作了這麼久的實戰,最後咱們能夠把前面學習到的內容應用到dmoz_spider這個爬蟲中。
在原爬蟲的parse函數中作以下修改: