第二節 http協議和Chrome抓包工具html
HTTP協議:全稱是HyperText Transfer Protocol
,中文意思是超文本傳輸協議,是一種發佈和接收HTML頁面的方法。服務器端口號是80
端口。 HTTPS協議:是HTTP協議的加密版本,在HTTP下加入了SSL層。服務器端口號是443
端口。前端
URL
是Uniform Resource Locator
的簡寫,統一資源定位符。 一個URL
由如下幾部分組成:python
scheme://host:port/path/?query-string=xxx#anchor
http
或者https
以及ftp
等。www.baidu.com
。www.jianshu.com/trending/now
,後面的trending/now
就是path
。www.baidu.com/s?wd=python
,後面的wd=python
就是查詢字符串。在瀏覽器中請求一個url
,瀏覽器會對這個url進行一個編碼。除英文字母,數字和部分符號外,其餘的所有使用百分號+十六進制碼值進行編碼。git
在Http
協議中,定義了八種請求方法。這裏介紹兩種經常使用的請求方法,分別是get
請求和post
請求。github
get
請求:通常狀況下,只從服務器獲取數據下來,並不會對服務器資源產生任何影響的時候會使用get
請求。post
請求:向服務器發送數據(登陸)、上傳文件等,會對服務器資源產生影響的時候會使用post
請求。 以上是在網站開發中經常使用的兩種方法。而且通常狀況下都會遵循使用的原則。可是有的網站和服務器爲了作反爬蟲機制,也常常會不按常理出牌,有可能一個應該使用get
方法的請求就必定要改爲post
請求,這個要視狀況而定。在http
協議中,向服務器發送一個請求,數據分爲三部分,第一個是把數據放在url中,第二個是把數據放在body
中(在post
請求中),第三個就是把數據放在head
中。這裏介紹在網絡爬蟲中常常會用到的一些請求頭參數:web
User-Agent
:瀏覽器名稱。這個在網絡爬蟲中常常會被使用到。請求一個網頁的時候,服務器經過這個參數就能夠知道這個請求是由哪一種瀏覽器發送的。若是咱們是經過爬蟲發送請求,那麼咱們的User-Agent
就是Python
,這對於那些有反爬蟲機制的網站來講,能夠輕易的判斷你這個請求是爬蟲。所以咱們要常常設置這個值爲一些瀏覽器的值,來假裝咱們的爬蟲。Referer
:代表當前這個請求是從哪一個url
過來的。這個通常也能夠用來作反爬蟲技術。若是不是從指定頁面過來的,那麼就不作相關的響應。Cookie
:http
協議是無狀態的。也就是同一我的發送了兩次請求,服務器沒有能力知道這兩個請求是否來自同一我的。所以這時候就用cookie
來作標識。通常若是想要作登陸後才能訪問的網站,那麼就須要發送cookie
信息了。200
:請求正常,服務器正常的返回數據。301
:永久重定向。好比在訪問www.jingdong.com
的時候會重定向到www.jd.com
。302
:臨時重定向。好比在訪問一個須要登陸的頁面的時候,而此時沒有登陸,那麼就會重定向到登陸頁面。400
:請求的url
在服務器上找不到。換句話說就是請求url
錯誤。403
:服務器拒絕訪問,權限不夠。500
:服務器內部錯誤。多是服務器出現bug
了。Chrome
瀏覽器是一個很是親近開發者的瀏覽器。能夠方便的查看網絡請求以及發送的參數。對着網頁右鍵->檢查
。而後就能夠打開開發者選項。redis
Elements: 構成這個網頁的源代碼。chrome
Console:這個網頁的控制檯。json
Sources:組成這個網頁的全部源文件。c#
Network:加載這個頁面時,瀏覽器發送的全部請求。
第三節 urllib庫
urllib
庫是Python
中一個最基本的網絡請求庫。能夠模擬瀏覽器的行爲,向指定的服務器發送一個請求,並能夠保存服務器返回的數據。
在Python3
的urllib
庫中,全部和網絡請求相關的方法,都被集到urllib.request
模塊下面了,以先來看下urlopen
函數基本的使用:
from urllib import request
resp = request.urlopen('http://www.baidu.com')
print(resp.read())
實際上,使用瀏覽器訪問百度,右鍵查看源代碼。你會發現,跟咱們剛纔打印出來的數據是如出一轍的。也就是說,上面的三行代碼就已經幫咱們把百度的首頁的所有代碼爬下來了。一個基本的url請求對應的python代碼真的很是簡單。 如下對urlopen
函數的進行詳細講解:
url
:請求的url。data
:請求的data
,若是設置了這個值,那麼將變成post
請求。http.client.HTTPResponse
對象,這個對象是一個類文件句柄對象。有read(size)
、readline
、readlines
以及getcode
等方法。這個函數能夠方便的將網頁上的一個文件保存到本地。如下代碼能夠很是方便的將百度的首頁下載到本地:
from urllib import request request.urlretrieve('http://www.baidu.com/','baidu.html')
urlencode函數:
用瀏覽器發送請求的時候,若是url中包含了中文或者其餘特殊字符,那麼瀏覽器會自動的給咱們進行編碼。而若是使用代碼發送請求,那麼就必須手動的進行編碼,這時候就應該使用urlencode
函數來實現。urlencode
能夠把字典數據轉換爲URL
編碼的數據。示例代碼以下:
from urllib import parse data = {'name':'爬蟲基礎','greet':'hello world','age':100} qs = parse.urlencode(data) print(qs)
能夠將通過編碼後的url參數進行解碼。示例代碼以下:
from urllib import parse qs = "name=%E7%88%AC%E8%99%AB%E5%9F%BA%E7%A1%80&greet=hello+world&age=100" print(parse.parse_qs(qs))
urlparse和urlsplit:
有時候拿到一個url,想要對這個url中的各個組成部分進行分割,那麼這時候就可使用urlparse
或者是urlsplit
來進行分割。示例代碼以下:
from urllib import request,parse url = 'http://www.baidu.com/s?username=zhiliao' result = parse.urlsplit(url) # result = parse.urlparse(url) print('scheme:',result.scheme) print('netloc:',result.netloc) print('path:',result.path) print('query:',result.query)
urlparse
和urlsplit
基本上是如出一轍的。惟一不同的地方是,urlparse
裏面多了一個params
屬性,而urlsplit
沒有這個params
屬性。好比有一個url
爲:url = 'http://www.baidu.com/s;hello?wd=python&username=abc#1'
, 那麼urlparse
能夠獲取到hello
,而urlsplit
不能夠獲取到。url
中的params
也用得比較少。
若是想要在請求的時候增長一些請求頭,那麼就必須使用request.Request
類來實現。好比要增長一個User-Agent
,示例代碼以下:
from urllib import request headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36' } req = request.Request("http://www.baidu.com/",headers=headers) resp = request.urlopen(req) print(resp.read())
不少網站會檢測某一段時間某個IP的訪問次數(經過流量統計,系統日誌等),若是訪問次數多的不像正常人,它會禁止這個IP的訪問。 因此咱們能夠設置一些代理服務器,每隔一段時間換一個代理,就算IP被禁止,依然能夠換個IP繼續爬取。 urllib中經過ProxyHandler來設置使用代理服務器,下面代碼說明如何使用自定義opener來使用代理:
from urllib import request # 這個是沒有使用代理的 # resp = request.urlopen('http://httpbin.org/get') # print(resp.read().decode("utf-8")) # 這個是使用了代理的 handler = request.ProxyHandler({"http":"218.66.161.88:31769"}) opener = request.build_opener(handler) req = request.Request("http://httpbin.org/ip") resp = opener.open(req) print(resp.read())
經常使用的代理有:
在網站中,http請求是無狀態的。也就是說即便第一次和服務器鏈接後而且登陸成功後,第二次請求服務器依然不能知道當前請求是哪一個用戶。cookie
的出現就是爲了解決這個問題,第一次登陸後服務器返回一些數據(cookie)給瀏覽器,而後瀏覽器保存在本地,當該用戶發送第二次請求的時候,就會自動的把上次請求存儲的cookie
數據自動的攜帶給服務器,服務器經過瀏覽器攜帶的數據就能判斷當前用戶是哪一個了。cookie
存儲的數據量有限,不一樣的瀏覽器有不一樣的存儲大小,但通常不超過4KB。所以使用cookie
只能存儲一些小量的數據。
Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
參數意義:
Cookie 是指網站服務器爲了辨別用戶身份和進行Session跟蹤,而儲存在用戶瀏覽器上的文本文件,Cookie能夠保持登陸信息到用戶下次與服務器的會話。 這裏以人人網爲例。人人網中,要訪問某我的的主頁,必須先登陸才能訪問,登陸說白了就是要有cookie信息。那麼若是咱們想要用代碼的方式訪問,就必需要有正確的cookie信息才能訪問。解決方案有兩種,第一種是使用瀏覽器訪問,而後將cookie信息複製下來,放到headers中。示例代碼以下:
from urllib import request headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36', 'Cookie': 'anonymid=jacdwz2x-8bjldx; depovince=GW; _r01_=1; _ga=GA1.2.1455063316.1511436360; _gid=GA1.2.862627163.1511436360; wp=1;
JSESSIONID=abczwY8ecd4xz8RJcyP-v; jebecookies=d4497791-9d41-4269-9e2b-3858d4989785|||||; ick_login=884e75d4-f361-4cff-94bb-81fe6c42b220;
_de=EA5778F44555C091303554EBBEB4676C696BF75400CE19CC; p=61a3c7d0d4b2d1e991095353f83fa2141; first_login_flag=1; ln_uact=970138074@qq.com;
ln_hurl=http://hdn.xnimg.cn/photos/hdn121/20170428/1700/main_nhiB_aebd0000854a1986.jpg; t=3dd84a3117737e819dd2c32f1cdb91d01;
societyguester=3dd84a3117737e819dd2c32f1cdb91d01; id=443362311; xnsid=169efdc0; loginfrom=syshome; ch_id=10016;
jebe_key=9c062f5a-4335-4a91-bf7a-970f8b86a64e%7Ca022c303305d1b2ab6b5089643e4b5de%7C1511449232839%7C1; wp_fold=0' } url = 'http://www.renren.com/880151247/profile' req = request.Request(url,headers=headers) resp = request.urlopen(req) with open('renren.html','w') as fp: fp.write(resp.read().decode('utf-8'))
可是每次在訪問須要cookie的頁面都要從瀏覽器中複製cookie比較麻煩。在Python處理Cookie,通常是經過http.cookiejar
模塊和urllib模塊的HTTPCookieProcessor
處理器類一塊兒使用。http.cookiejar
模塊主要做用是提供用於存儲cookie的對象。而HTTPCookieProcessor
處理器主要做用是處理這些cookie對象,並構建handler對象。
該模塊主要的類有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。這四個類的做用分別以下:
利用http.cookiejar
和request.HTTPCookieProcessor
登陸人人網。相關示例代碼以下:
from urllib import request,parse from http.cookiejar import CookieJar headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36' } def get_opener(): cookiejar = CookieJar() handler = request.HTTPCookieProcessor(cookiejar) opener = request.build_opener(handler) return opener def login_renren(opener): data = {"email": "970138074@qq.com", "password": "pythonspider"} data = parse.urlencode(data).encode('utf-8') login_url = "http://www.renren.com/PLogin.do" req = request.Request(login_url, headers=headers, data=data) opener.open(req) def visit_profile(opener): url = 'http://www.renren.com/880151247/profile' req = request.Request(url,headers=headers) resp = opener.open(req) with open('renren.html','w') as fp: fp.write(resp.read().decode("utf-8")) if __name__ == '__main__': opener = get_opener() login_renren(opener) visit_profile(opener)
保存cookie
到本地,可使用cookiejar
的save
方法,而且須要指定一個文件名:
from urllib import request from http.cookiejar import MozillaCookieJar cookiejar = MozillaCookieJar("cookie.txt") handler = request.HTTPCookieProcessor(cookiejar) opener = request.build_opener(handler) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36' } req = request.Request('http://httpbin.org/cookies',headers=headers) resp = opener.open(req) print(resp.read()) cookiejar.save(ignore_discard=True,ignore_expires=True)
從本地加載cookie
,須要使用cookiejar
的load
方法,而且也須要指定方法:
from urllib import request from http.cookiejar import MozillaCookieJar cookiejar = MozillaCookieJar("cookie.txt") cookiejar.load(ignore_expires=True,ignore_discard=True) handler = request.HTTPCookieProcessor(cookiejar) opener = request.build_opener(handler) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36' } req = request.Request('http://httpbin.org/cookies',headers=headers) resp = opener.open(req) print(resp.read())
雖然Python的標準庫中 urllib模塊已經包含了日常咱們使用的大多數功能,可是它的 API 使用起來讓人感受不太好,而 Requests宣傳是 「HTTP for Humans」,說明使用更簡潔方便。
利用pip
能夠很是方便的安裝:
pip install requests
中文文檔:http://docs.python-requests.org/zh_CN/latest/index.html
github地址:https://github.com/requests/requests
最簡單的發送get
請求就是經過requests.get
來調用:
response = requests.get("http://www.baidu.com/")
添加headers和查詢參數: 若是想添加 headers,能夠傳入headers參數來增長請求頭中的headers信息。若是要將參數放在url中傳遞,能夠利用 params 參數。相關示例代碼以下:
import requests kw = {'wd':'中國'} headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} # params 接收一個字典或者字符串的查詢參數,字典類型自動轉換爲url編碼,不須要urlencode() response = requests.get("http://www.baidu.com/s", params = kw, headers = headers) # 查看響應內容,response.text 返回的是Unicode格式的數據 print(response.text) # 查看響應內容,response.content返回的字節流數據 print(response.content) # 查看完整url地址 print(response.url) # 查看響應頭部字符編碼 print(response.encoding) # 查看響應碼 print(response.status_code)
註釋:response.text和response.content的區別: 1.response.text:這是個str的數據類型,是requests庫將response.content進行解碼的字符串,解碼須要制定一個編碼方式,requests會根據本身的猜想來判斷編碼的方式。因此有時候可能會有猜想錯誤,就會致使解碼產生亂碼,這時候就應該使用response.content.decode('utf-8')進行手動解碼。 2.response.content:這個是直接從網絡上面抓取的數據。沒有通過任何解碼。因此是一個bytes類型。其實在硬盤上和網絡上傳輸的字符串都是bytes類型。
最基本的POST請求可使用post
方法:
response = requests.post("http://www.baidu.com/",data=data)
傳入data數據: 這時候就不要再使用urlencode
進行編碼了,直接傳入一個字典進去就能夠了。好比請求拉勾網的數據的代碼:
import requests url = "https://www.lagou.com/jobs/positionAjax.json?city=%E6%B7%B1%E5%9C%B3&needAddtionalResult=false&isSchoolJob=0" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36', 'Referer': 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=' } data = { 'first': 'true', 'pn': 1, 'kd': 'python' } resp = requests.post(url,headers=headers,data=data) # 若是是json數據,直接能夠調用json方法 print(resp.json())
註釋:發送post請求很是簡單,直接調用「requests.post」方法就好了。若是返回的是json數據,那麼能夠調用「response.json()」來將json字符串轉換爲字典或者列表。
使用requests
添加代理也很是簡單,只要在請求的方法中(好比get
或者post
)傳遞proxies
參數就能夠了。示例代碼以下:
import requests url = "http://httpbin.org/get" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36', } proxy = { 'http': '171.14.209.180:27829' } resp = requests.get(url,headers=headers,proxies=proxy) with open('xx.html','w',encoding='utf-8') as fp: fp.write(resp.text)
註釋:在請求方法中,傳遞「proxies」參數就能夠了。
cookie:
若是在一個響應中包含了cookie
,那麼能夠利用cookies
屬性拿到這個返回的cookie
值:
import requests url = "http://www.renren.com/PLogin.do" data = {"email":"970138074@qq.com",'password':"pythonspider"} resp = requests.get('http://www.baidu.com/') print(resp.cookies) print(resp.cookies.get_dict())
註釋:若是想要在屢次請求中共享cookie,那麼應該使用session。
以前使用urllib
庫,是可使用opener
發送多個請求,多個請求之間是能夠共享cookie
的。那麼若是使用requests
,也要達到共享cookie
的目的,那麼可使用requests
庫給咱們提供的session
對象。注意,這裏的session
不是web開發中的那個session,這個地方只是一個會話的對象而已。仍是以登陸人人網爲例,使用requests
來實現。示例代碼以下:
import requests url = "http://www.renren.com/PLogin.do" data = {"email":"970138074@qq.com",'password':"pythonspider"} headers = { 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36" } # 登陸 session = requests.session() session.post(url,data=data,headers=headers) # 訪問大鵬我的中心 resp = session.get('http://www.renren.com/880151247/profile') print(resp.text)
對於那些已經被信任的SSL整數的網站,好比https://www.baidu.com/
,那麼使用requests
直接就能夠正常的返回響應。示例代碼以下:
resp = requests.get('http://www.12306.cn/mormhweb/',verify=False) print(resp.content.decode('utf-8'))