網絡爬蟲(又被稱爲網頁蜘蛛,網絡機器人,在FOAF社區中間,更常常的稱爲網頁追逐者),是一種按照必定的規則,自動地抓取萬維網信息的程序或者腳本。另一些不常使用的名字還有螞蟻、自動索引、模擬程序或者蠕蟲。css
其實通俗的講就是經過程序去獲取web頁面上本身想要的數據,也就是自動抓取數據。html
你能夠爬去妹子的圖片,爬取本身想看看的視頻。。等等你想要爬取的數據,只要你能經過瀏覽器訪問的數據均可以經過爬蟲獲取python
模擬瀏覽器打開網頁,獲取網頁中咱們想要的那部分數據mysql
瀏覽器打開網頁的過程:
當你在瀏覽器中輸入地址後,通過DNS服務器找到服務器主機,向服務器發送一個請求,服務器通過解析後發送給用戶瀏覽器結果,包括html,js,css等文件內容,瀏覽器解析出來最後呈現給用戶在瀏覽器上看到的結果git
因此用戶看到的瀏覽器的結果就是由HTML代碼構成的,咱們爬蟲就是爲了獲取這些內容,經過分析和過濾html代碼,從中獲取咱們想要資源(文本,圖片,視頻.....)web
發起請求
經過HTTP庫向目標站點發起請求,也就是發送一個Request,請求能夠包含額外的header等信息,等待服務器響應ajax
獲取響應內容
若是服務器能正常響應,會獲得一個Response,Response的內容即是所要獲取的頁面內容,類型多是HTML,Json字符串,二進制數據(圖片或者視頻)等類型正則表達式
解析內容
獲得的內容多是HTML,能夠用正則表達式,頁面解析庫進行解析,多是Json,能夠直接轉換爲Json對象解析,多是二進制數據,能夠作保存或者進一步的處理sql
保存數據
保存形式多樣,能夠存爲文本,也能夠保存到數據庫,或者保存特定格式的文件chrome
瀏覽器發送消息給網址所在的服務器,這個過程就叫作HTPP Request
服務器收到瀏覽器發送的消息後,可以根據瀏覽器發送消息的內容,作相應的處理,而後把消息回傳給瀏覽器,這個過程就是HTTP Response
瀏覽器收到服務器的Response信息後,會對信息進行相應的處理,而後展現
請求方式
主要有:GET/POST兩種類型經常使用,另外還有HEAD/PUT/DELETE/OPTIONS
GET和POST的區別就是:請求的數據GET是在url中,POST則是存放在頭部
GET:向指定的資源發出「顯示」請求。使用GET方法應該只用在讀取數據,而不該當被用於產生「反作用」的操做中,例如在Web Application中。其中一個緣由是GET可能會被網絡蜘蛛等隨意訪問
POST:向指定資源提交數據,請求服務器進行處理(例如提交表單或者上傳文件)。數據被包含在請求本文中。這個請求可能會建立新的資源或修改現有資源,或兩者皆有。
HEAD:與GET方法同樣,都是向服務器發出指定資源的請求。只不過服務器將不傳回資源的本文部分。它的好處在於,使用這個方法能夠在沒必要傳輸所有內容的狀況下,就能夠獲取其中「關於該資源的信息」(元信息或稱元數據)。
PUT:向指定資源位置上傳其最新內容。
OPTIONS:這個方法可以使服務器傳回該資源所支持的全部HTTP請求方法。用'*'來代替資源名稱,向Web服務器發送OPTIONS請求,能夠測試服務器功能是否正常運做。
DELETE:請求服務器刪除Request-URI所標識的資源。
請求URL
URL,即統一資源定位符,也就是咱們說的網址,統一資源定位符是對能夠從互聯網上獲得的資源的位置和訪問方法的一種簡潔的表示,是互聯網上標準資源的地址。互聯網上的每一個文件都有一個惟一的URL,它包含的信息指出文件的位置以及瀏覽器應該怎麼處理它。
URL的格式由三個部分組成:
第一部分是協議(或稱爲服務方式)。
第二部分是存有該資源的主機IP地址(有時也包括端口號)。
第三部分是主機資源的具體地址,如目錄和文件名等。
爬蟲爬取數據時必需要有一個目標的URL才能夠獲取數據,所以,它是爬蟲獲取數據的基本依據。
請求頭
包含請求時的頭部信息,如User-Agent,Host,Cookies等信息,下圖是請求請求百度時,全部的請求頭部信息參數
請求體
請求是攜帶的數據,如提交表單數據時候的表單數據(POST)
全部HTTP響應的第一行都是狀態行,依次是當前HTTP版本號,3位數字組成的狀態代碼,以及描述狀態的短語,彼此由空格分隔。
響應狀態
有多種響應狀態,如:200表明成功,301跳轉,404找不到頁面,502服務器錯誤
響應頭
如內容類型,類型的長度,服務器信息,設置Cookie,以下圖
響應體
最主要的部分,包含請求資源的內容,如網頁HTMl,圖片,二進制數據等
網頁文本:如HTML文檔,Json格式化文本等
圖片:獲取到的是二進制文件,保存爲圖片格式
視頻:一樣是二進制文件
其餘:只要請求到的,均可以獲取
出現這種狀況是由於,不少網站中的數據都是經過js,ajax動態加載的,因此直接經過get請求獲取的頁面和瀏覽器顯示的不一樣。
如何解決js渲染的問題?
分析ajax
Selenium/webdriver
Splash
PyV8,Ghost.py
文本:純文本,Json,Xml等
關係型數據庫:如mysql,oracle,sql server等結構化數據庫
非關係型數據庫:MongoDB,Redis等key-value形式存儲
Requests是用python語言基於urllib編寫的,採用的是Apache2 Licensed開源協議的HTTP庫
若是你看過上篇文章關於urllib庫的使用,你會發現,其實urllib仍是很是不方便的,而Requests它會比urllib更加方便,能夠節約咱們大量的工做。(用了requests以後,你基本都不肯意用urllib了)一句話,requests是python實現的最簡單易用的HTTP庫,建議爬蟲使用requests庫。
默認安裝好python以後,是沒有安裝requests模塊的,須要單獨經過pip安裝
import requests response = requests.get("https://www.baidu.com") print(type(response)) print(response.status_code) print(type(response.text)) print(response.text) print(response.cookies) print(response.content) print(response.content.decode("utf-8"))
咱們能夠看出response使用起來確實很是方便,這裏有個問題須要注意一下:
不少狀況下的網站若是直接response.text會出現亂碼的問題,因此這個使用response.content
這樣返回的數據格式實際上是二進制格式,而後經過decode()轉換爲utf-8,這樣就解決了經過response.text直接返回顯示亂碼的問題.
請求發出後,Requests 會基於 HTTP 頭部對響應的編碼做出有根據的推測。當你訪問 response.text 之時,Requests 會使用其推測的文本編碼。你能夠找出 Requests 使用了什麼編碼,而且可以使用 response.encoding 屬性來改變它.如:
response =requests.get("http://www.baidu.com") response.encoding="utf-8" print(response.text)
不論是經過response.content.decode("utf-8)的方式仍是經過response.encoding="utf-8"的方式均可以免亂碼的問題發生
requests裏提供個各類請求方式
import requests 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")
請求
基本GET請求
import requests response = requests.get('http://httpbin.org/get') print(response.text)
帶參數的GET請求,例子1
import requests response = requests.get("http://httpbin.org/get?name=zhaofan&age=23") print(response.text)
若是咱們想要在URL查詢字符串傳遞數據,一般咱們會經過httpbin.org/get?key=val方式傳遞。Requests模塊容許使用params關鍵字傳遞參數,以一個字典來傳遞這些參數,例子以下:
import requests data = { "name":"zhaofan", "age":22 } response = requests.get("http://httpbin.org/get",params=data) print(response.url) print(response.text)
上述兩種的結果是相同的,經過params參數傳遞一個字典內容,從而直接構造url
注意:第二種方式經過字典的方式的時候,若是字典中的參數爲None則不會添加到url上
解析json
import requests import json response = requests.get("http://httpbin.org/get") print(type(response.text)) print(response.json()) print(json.loads(response.text)) print(type(response.json()))
從結果能夠看出requests裏面集成的json其實就是執行了json.loads()方法,二者的結果是同樣的
獲取二進制數據
在上面提到了response.content,這樣獲取的數據是二進制數據,一樣的這個方法也能夠用於下載圖片以及
視頻資源
添加headers
和前面咱們將urllib模塊的時候同樣,咱們一樣能夠定製headers的信息,如當咱們直接經過requests請求知乎網站的時候,默認是沒法訪問的
import requests response =requests.get("https://www.zhihu.com") print(response.text)
這樣會獲得以下的錯誤
由於訪問知乎須要頭部信息,這個時候咱們在谷歌瀏覽器裏輸入chrome://version,就能夠看到用戶代理,將用戶代理添加到頭部信息
import requests headers = { "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" } response =requests.get("https://www.zhihu.com",headers=headers) print(response.text)
這樣就能夠正常的訪問知乎了
基本POST請求
經過在發送post請求時添加一個data參數,這個data參數能夠經過字典構形成,這樣
對於發送post請求就很是方便
import requests data = { "name":"zhaofan", "age":23 } response = requests.post("http://httpbin.org/post",data=data) print(response.text)
一樣的在發送post請求的時候也能夠和發送get請求同樣經過headers參數傳遞一個字典類型的數據
響應
咱們能夠經過response得到不少屬性,例子以下
import requests response = requests.get("http://www.baidu.com") print(type(response.status_code),response.status_code) print(type(response.headers),response.headers) print(type(response.cookies),response.cookies) print(type(response.url),response.url) print(type(response.history),response.history)
結果以下:
狀態碼判斷
Requests還附帶了一個內置的狀態碼查詢對象
主要有以下內容:
100: ('continue',),
101: ('switching_protocols',),
102: ('processing',),
103: ('checkpoint',),
122: ('uri_too_long', 'request_uri_too_long'),
200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\o/', '✓'),
201: ('created',),
202: ('accepted',),
203: ('non_authoritative_info', 'non_authoritative_information'),
204: ('no_content',),
205: ('reset_content', 'reset'),
206: ('partial_content', 'partial'),
207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'),
208: ('already_reported',),
226: ('im_used',),
Redirection.
300: ('multiple_choices',),
301: ('moved_permanently', 'moved', '\o-'),
302: ('found',),
303: ('see_other', 'other'),
304: ('not_modified',),
305: ('use_proxy',),
306: ('switch_proxy',),
307: ('temporary_redirect', 'temporary_moved', 'temporary'),
308: ('permanent_redirect',
'resume_incomplete', 'resume',), # These 2 to be removed in 3.0
Client Error.
400: ('bad_request', 'bad'),
401: ('unauthorized',),
402: ('payment_required', 'payment'),
403: ('forbidden',),
404: ('not_found', '-o-'),
405: ('method_not_allowed', 'not_allowed'),
406: ('not_acceptable',),
407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'),
408: ('request_timeout', 'timeout'),
409: ('conflict',),
410: ('gone',),
411: ('length_required',),
412: ('precondition_failed', 'precondition'),
413: ('request_entity_too_large',),
414: ('request_uri_too_large',),
415: ('unsupported_media_type', 'unsupported_media', 'media_type'),
416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'),
417: ('expectation_failed',),
418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'),
421: ('misdirected_request',),
422: ('unprocessable_entity', 'unprocessable'),
423: ('locked',),
424: ('failed_dependency', 'dependency'),
425: ('unordered_collection', 'unordered'),
426: ('upgrade_required', 'upgrade'),
428: ('precondition_required', 'precondition'),
429: ('too_many_requests', 'too_many'),
431: ('header_fields_too_large', 'fields_too_large'),
444: ('no_response', 'none'),
449: ('retry_with', 'retry'),
450: ('blocked_by_windows_parental_controls', 'parental_controls'),
451: ('unavailable_for_legal_reasons', 'legal_reasons'),
499: ('client_closed_request',),
Server Error.
500: ('internal_server_error', 'server_error', '/o\', '✗'),
501: ('not_implemented',),
502: ('bad_gateway',),
503: ('service_unavailable', 'unavailable'),
504: ('gateway_timeout',),
505: ('http_version_not_supported', 'http_version'),
506: ('variant_also_negotiates',),
507: ('insufficient_storage',),
509: ('bandwidth_limit_exceeded', 'bandwidth'),
510: ('not_extended',),
511: ('network_authentication_required', 'network_auth', 'network_authentication'),
經過下面例子測試:(不過一般仍是經過狀態碼判斷更方便)
import requests response= requests.get("http://www.baidu.com") if response.status_code == requests.codes.ok: print("訪問成功")
文件上傳
實現方法和其餘參數相似,也是構造一個字典而後經過files參數傳遞
import requests files= {"files":open("git.jpeg","rb")} response = requests.post("http://httpbin.org/post",files=files) print(response.text)
結果以下:
獲取cookie
import requests response = requests.get("http://www.baidu.com") print(response.cookies) for key,value in response.cookies.items(): print(key+"="+value)
會話維持
cookie的一個做用就是能夠用於模擬登錄,作會話維持
import requests s = requests.Session() s.get("http://httpbin.org/cookies/set/number/123456") response = s.get("http://httpbin.org/cookies") print(response.text)
這是正確的寫法,而下面的寫法則是錯誤的
import requests requests.get("http://httpbin.org/cookies/set/number/123456") response = requests.get("http://httpbin.org/cookies") print(response.text)
心得體會
request是最基本的爬蟲庫了, 建議新手把測試案例都運行一下,體會一下爬蟲的過程。
體會一下模擬瀏覽器訪問各個階段、數據是如何交互的、如何處理的。