Python爬蟲 | cookies的使用

1、簡介

cookie概念html

  當用戶經過瀏覽器首次訪問一個域名時,訪問的web服務器會給客戶端發送數據,以保持web服務器與客戶端之間的狀態保持,這些數據就是cookie。nginx

 Cookie 是指某些網站服務器爲了辨別用戶身份和進行Session跟蹤,而儲存在用戶瀏覽器上的文本文件,Cookie能夠保持登陸信息到用戶下次與服務器的會話。web

爲何會有cookie呢?chrome

  由於http和https都是短連接,連接成功以後連接立刻斷開了。服務端是不會保存客戶端的相關信息的。因此,服務端和客戶端是沒有辦法創建一個長連接的。爲了讓服務端長久的記錄客戶端的狀態。纔會產生cookie這樣一種機制。客戶端第一次訪問服務端的時候,服務端會給客戶端建立一次會話,會給客戶端建立一個cookie,用來讓服務器端記錄客戶端相關的狀態的。服務器端把cookie建立好以後,cookie不會存在服務器端,會讓服務器端發送給客戶端,會保存到客戶端瀏覽器本地。一旦存到客戶端以後,客戶端下次向服務器發請求的時候,就能夠攜帶這個cookie了。服務端就能夠收到這個cookie,服務端就會根據這個cookie來斷定當前客戶端是怎麼樣的狀態。django

 

Cookie是http消息頭中的一種屬性,包括:json

Cookie名字(Name) Cookie的值(Value) Cookie的過時時間(Expires/Max-Age) Cookie做用路徑(Path) Cookie所在域名(Domain), 使用Cookie進行安全鏈接(Secure)。 

前兩個參數是Cookie應用的必要條件,另外,還包括Cookie大小(Size,不一樣瀏覽器對Cookie個數及大小限制是有差別的)。api

 

Cookie由變量名和值組成,根據 Netscape公司的規定,Cookie格式以下:瀏覽器

Set-Cookie: NAME=VALUE;Expires=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE

 

 

2、cookie 使用

     - 手動處理:將cookie添加到headers安全

     - 自動處理:使用會話對象requests.Session(),會話對象能夠向requests模塊同樣進行請求的發送。服務器

 

案例1:

在爬取豆瓣的數據時發現了一些問題。由於要作一個爬蟲,爬取用戶讀過的書以及對書的評分。可是在進行網頁的分析時卻出現了點問題。 當瀏覽器打開用戶讀書記錄的連接時是沒有任何問題的,可是用requests庫來進行網頁爬取時卻出現了問題。 以https://book.douban.com/people/…/collect這個連接爲例,獲取這個連接的html源碼,通常都是這樣寫: 

import requests url = 'https://book.douban.com/people/.../collect' r = requests.get(url) print(r.text)

 

運行結果倒是: 

<html>
    <head><title>403 Forbidden</title></head>
<body bgcolor="white">
    <center><h1>403 Forbidden</h1></center>
    <hr><center>nginx</center>
</body>
</html>

網頁卻能正常訪問

 

通過百度後發現,這是由於在爬取網頁時沒有傳入Cookie,服務器不能識別用戶身份,網頁不能顯示給沒有用戶身份的請求,因此網頁源碼被隱藏了。所以,要在請求時加上Cookie,如何獲取Cookie? 不能https://book.douban.com/people/…/collect這個連接中直接獲取Cookie,由於這個連接在缺乏Cookie的狀況下根本不能正常訪問。可是能夠登陸豆瓣官網來獲取Cookie,登陸豆瓣官網不須要Cookie。

import urllib.request import http.cookiejar /*設置文件來存儲Cookie*/ filename = 'cookie.txt'

/*建立一個MozillaCookieJar()對象實例來保存Cookie*/ cookie = http.cookiejar.MozillaCookieJar(filename) /*建立Cookie處理器*/ handler = urllib.request.HTTPCookieProcessor(cookie) /*構建opener*/ opener = urllib.request.build_opener(handler) response = opener.open("https://www.douban.com/") cookie.save(ignore_discard=True, ignore_expires=True)

打開cookie.txt文件會發現cookie已被保存。

這樣在訪問用戶讀過的書的連接時,從文件中讀取Cookie,在進行網頁請求時加上Cookie就好了。 

import requests import http.cookiejar cookie = http.cookiejar.MozillaCookieJar() /*加載Cookie*/ cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True) url = 'https://book.douban.com/people/.../collect' r = requests.get(url, cookies=cookie) print(r.text)123456789 

運行結果:

<!DOCTYPE html>
<html lang="zh-cmn-Hans" class=" book-new-nav">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title> 讀過的書(219) </title>

<script>!function(e){var o=function(o,n,t){var c,i,r=new Date;n=n||30,t=t||"/",r.setTime(r.getTime()+24*n*60*60*1e3),c="; expires="+r.toGMTString();for(i in o)e.cookie=i+"="+o[i]+c+"; path="+t},n=function(o){var n,t,c,i=o+"=",r=e.cookie.split(";");for(t=0,c=r.length;t<c;t++)if(n=r[t].replace(/^\s+|\s+$/g,""),0==n.indexOf(i))return n.substring(i.length,n.length).replace(/\"/g,"");return null},t=e.write,c={"douban.com":1,"douban.fm":1,"google.com":1,"google.cn":1,"googleapis.com":1,"gmaptiles.co.kr":1,"gstatic.com":1,"gstatic.cn":1,"google-analytics.com":1,"googleadservices.com":1},i=function(e,o){var n=new Image;n.οnlοad=function(){},n.src="https://www.douban.com/j/except_report?kind=ra022&reason="+encodeURIComponent(e)+"&environment="+encodeURIComponent(o)},r=function(o){try{t.call(e,o)}catch(e){t(o)}},a=/<script.*?src\=["']?([^"'\s>]+)/gi,g=/http:\/\/(.+?)\.([^\/]+).+/i;e.writeln=e.write=function(e){var t,l=a.exec(e);return l&&(t=g.exec(l[1]))?c[t[2]]?void r(e):void("tqs"!==n("hj")&&(i(l[1],location.href),o({hj:"tqs"},1),setTimeout(function(){location.replace(location.href)},50))):void r(e)}}(document); </script>
View Code

 

案例2:僞造cookie

爬取豆瓣時卻出了問題: 豆瓣封IP,白天一分鐘能夠訪問40次,晚上一分鐘能夠訪問60次,超過限制次數就會封IP。 即便使用代理IP,可是一旦超過限制次數爬蟲仍然不能正常訪問豆瓣。 問題出在Cookie上 ,豆瓣利用封IP+封Cookie來限制爬蟲,所以只用代理IP的話也不行,Cookie也要更換。 

  • 想法1: 每次使用代理IP時,先訪問豆瓣官網獲取Cookie再訪問用戶的評論頁面。本覺得換了IP,Cookie隨之也會更換,其實Cookie並無改變。 
  • 想法2: 僞造Cookie。 觀察豆瓣設置的Cookie格式,並進行僞造。
import requests r = requests.get('https://www.douban.com/') print(r.cookies) ''' <RequestsCookieJar[<Cookie bid=UTM5r4DvtLY for .douban.com/>, <Cookie ll="118237" for .douban.com/>]> '''

下圖是第一次訪問豆瓣官網時,豆瓣創建Cookie的格式。若是已經訪問過,能夠把Cookie的信息刪除再訪問。

而後,根據Set-Cookie的格式構造Cookie就好了。 先構造一個Cookie試試:

import requests jar = requests.cookies.RequestsCookieJar() jar.set('tasty_cookie', 'yum', domain='.douban.com', path='/cookies') url = 'https://book.douban.com/people/122624856/collect' r = requests.get(url, cookies=jar) print(r.text)

運行結果:

<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

按照豆瓣的格式來構造Cookie:

import requests jar = requests.cookies.RequestsCookieJar() jar.set('bid', 'ehjk9OLdwha', domain='.douban.com', path='/') jar.set('11', '25678', domain='.douban.com', path='/') url = 'https://book.douban.com/people/122624856/collect' r = requests.get(url, cookies=jar) print(r.text)

運行結果:

<!DOCTYPE html>
<html lang="zh-cmn-Hans" class=" book-new-nav">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title> 北渺讀過的書(175) </title>

<script>!function(e){var o=function(o,n,t){var c,i,r=new Date;n=n||30,t=t||"/",r.setTime(r.getTime()+24*n*60*60*1e3),c="; expires="+r.toGMTString();for(i in o)e.cookie=i+"="+o[i]+c+"; path="+t},n=function(o){var n,t,c,i=o+"=",r=e.cookie.split(";");for(t=0,c=r.length;t<c;t++)if(n=r[t].replace(/^\s+|\s+$/g,""),0==n.indexOf(i))return n.substring(i.length,n.length).replace(/\"/g,"");return null},t=e.write,c={"douban.com":1,"douban.fm":1,"google.com":1,"google.cn":1,"googleapis.com":1,"gmaptiles.co.kr":1,"gstatic.com":1,"gstatic.cn":1,"google-analytics.com":1,"googleadservices.com":1},i=function(e,o){var n=new Image;n.οnlοad=function(){},n.src="https://www.douban.com/j/except_report?kind=ra022&reason="+encodeURIComponent(e)+"&environment="+encodeURIComponent(o)},r=function(o){try{t.call(e,o)}catch(e){t(o)}},a=/<script.*?src\=["']?([^"'\s>]+)/gi,g=/http:\/\/(.+?)\.([^\/]+).+/i;e.writeln=e.write=function(e){var t,l=a.exec(e);return l&&(t=g.exec(l[1]))?c[t[2]]?void r(e):void("tqs"!==n("hj")&&(i(l[1],location.href),o({hj:"tqs"},1),setTimeout(function(){location.replace(location.href)},50))):void r(e)}}(document); </script>
View Code

 

案例3:雪球網,爬取新聞標題和內容

1 import requests 2 from lxml import etree 3 headers = { 4     'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
 5 } 6 
 7 # 建立一個會話對象:能夠像requests模塊同樣發起請求。若是請求過程當中產生cookie的話,則cookie會被會話自動處理
 8 s = requests.Session() 9 first_url = 'https://xueqiu.com/'
10 
11 # 請求過程當中會產生cookie,cookie就會被存儲到session對象中,從起始url獲取cookie
12 s.get(url=first_url,headers=headers) 13 
14 
15 url = 'https://xueqiu.com/v4/statuses/public_timeline_by_category.json?since_id=-1&max_id=-1&count=10&category=-1'
16 
17 #攜帶cookie,對url進行請求發送。# 這裏不能用request發送,要用session對象
18 json_obj = s.get(url=url,headers=headers).json() 19 print(json_obj)

 

案例4模擬登陸古詩文網

  請求這個驗證碼圖片的時候,也會產生cookie,模擬登錄的時候須要使用這張圖片所對應的cookie,因此直接使用session發送請求。這個案例總共保存了2組cookie , 一組是驗證碼的,一組是登陸信息的。

1 import requests 2 import urllib 3 from lxml import etree 4 headers = { 5     'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
 6 } 7 s = requests.Session() 8 login_url = 'https://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx'
 9 page_text = requests.get(url=login_url,headers=headers).text 10 tree = etree.HTML(page_text) 11 img_src = 'https://so.gushiwen.org'+tree.xpath('//*[@id="imgCode"]/@src')[0] 12 img_data = s.get(url=img_src,headers=headers).content 13 with open('./img.jpg','wb') as fp: 14 fp.write(img_data) 15 img_text = getCodeDate('bobo328410948','bobo328410948','./img.jpg',1004) 16 
17 #模擬登陸
18 url = 'https://so.gushiwen.org/user/login.aspx?from=http%3a%2f%2fso.gushiwen.org%2fuser%2fcollect.aspx'
19 data = { 20     "__VIEWSTATE":"9AsGvh3Je/0pfxId7DYRUi258ayuEG4rrQ1Z3abBgLoDSOeAUatOZOrAIxudqiOauXpR9Zq+dmKJ28+AGjXYHaCZJTTtGgrEemBWI1ed7oS7kpB7Rm/4yma/+9Q=", 21     "__VIEWSTATEGENERATOR":"C93BE1AE", 22     "from":"http://so.gushiwen.org/user/collect.aspx", 23     "email":"xxx@qq.com", 24     "pwd":"*****", 25     "code":img_text, 26     "denglu":"登陸", 27 } 28 page_text = s.post(url=url,headers=headers,data=data).text 29 with open('./gushiwen.html','w',encoding='utf-8') as fp: 30     fp.write(page_text)

 

3、爬蟲中獲取cookie的方式

爲何要獲取cookie?

  由於有的頁面爬取的時候,須要登陸後才能爬,好比知乎,如何判斷一個頁面是否已經登陸,經過判斷是否含有cookies就能夠,咱們獲取到cookie後就能夠攜帶cookie來訪問須要登陸後的頁面了。

 

方式一:使用session

這裏的session並非django中的session,而是requests中的session

import requests url = 'https://www.processon.com/login' login_email = '286933867@qq.com' login_password = 'ZZZ05382881391'

# 建立一個session,做用會自動保存cookie
session = requests.session() data = { 'login_email': login_email, 'login_password': login_password } # 使用session發起post請求來獲取登陸後的cookie,cookie已經存在session中
response = session.post(url = url,data=data) # 用session給我的主頁發送請求,由於session中已經有cookie了
index_url = 'https://www.processon.com/diagrams' index_page = session.get(url=index_url).text print(index_page)

把cookie保存在本地,並判斷用戶是否已經登陸。

import requests from http import cookiejar # 建立一個session,做用會自動保存cookie
session = requests.session() # 指定cookie保存的路徑
session.cookies = cookiejar.LWPCookieJar(filename="cookies.txt") try: session.cookies.load(ignore_discard=True)  # 加載cookie文件,ignore_discard = True,即便cookie被拋棄,也要保存下來
except: print('cookie未能加載') def login_save_cookie(): """ 登陸並保存cookie到本地 :return: """ url = 'https://www.processon.com/login' login_email = '*****@qq.com' login_password = '****1391' data = { 'login_email': login_email, 'login_password': login_password } # 使用session發起post請求來獲取登陸後的cookie,cookie已經存在session中
    response = session.post(url=url, data=data) # 把cookie保存到文件中
 session.cookies.save() def read_cookie(): """ 讀取cookie進入登陸後的頁面 :return: """ index_url = 'https://www.processon.com/diagrams' index_page = session.get(url=index_url).text print(index_page) def login_y_n(): """ 判斷用戶是否已經登陸,咱們這裏使用的方法是:隨便找一個登錄後頁面的url,若是咱們訪問它時不發生重定向,咱們就能夠 判斷該用戶應經登陸了 :return: """ url = 'https://www.processon.com/diagrams/new#template' response = session.get(url = url,allow_redirects=False) # allow_redirects =False不容許重定向到登陸頁面
    if response != 200: return False else: return True read_cookie()

 

方法二:使用selenium獲取cookies

from selenium import webdriver import json browser = webdriver.Chrome(executable_path=r"E:\chromedriver_win32_2.46\chromedriver.exe") def get_cookies(): """ 經過selenium獲取cookie保存在文件中 :return: """ url = 'https://www.processon.com/login' browser.get(url=url) browser.find_element_by_id('login_email').send_keys('286933867@qq.com') browser.find_element_by_id('login_password').send_keys('ZZZ05382881391') browser.find_element_by_id('signin_btn').click()
# 獲取cookie,這裏獲得的是一個列表 cookies_list = browser.get_cookies() browser.close() with open("cookies.txt", "w") as fp: json.dump(cookies_list, fp) # 這裏切記,若是咱們要使用json.load讀取數據,那麼必定要使用json.dump來寫入數據, # 不能使用str(cookies)直接轉爲字符串進行保存,由於其存儲格式不一樣。這樣咱們就將cookies保存在文件中了。 def read_cookie(): """ 讀取cookie,添加到browser中 :return: """ url = 'https://www.processon.com/diagrams' browser.get(url=url) # 這裏必須先訪問一次不然頁面不能打開 with open('./cookies.txt','r') as fp: cookies_list = json.load(fp) for cookies in cookies_list: browser.add_cookie(cookies) browser.get(url) read_cookie()

注意:用selenium來獲取的cookie是一個列表,列表中有不少字典,字典中有domain、expiry、name、value、path等key,可是在咱們真正的瀏覽器中就只有一個字典,字典中只有name 鍵對應的值和value對應的值,因此在使用的時候還須要轉換一下:

[{"domain": ".processon.com", "expiry": 1560351255.689168, "httpOnly": false, "name": "_sid", "path": "/", "secure": false, "value": "796afe66ce2a6002828ab3ca281f96fb"}, {"domain": ".processon.com", "httpOnly": true, "name": "JSESSIONID", "path": "/", "secure": false, "value": "EBDACE1BDAB1464A2CCBBFFB7048A238.jvm1"}, {"domain": ".processon.com", "expiry": 1586703257, "httpOnly": false, "name": "zg_did", "path": "/", "secure": false, "value": "%7B%22did%22%3A%20%2216a173113351bb-062c441b2e33b7-7a1437-144000-16a173113362e%22%7D"}, {"domain": ".processon.com", "expiry": 1560351255.689117, "httpOnly": false, "name": "processon_userKey", "path": "/", "secure": false, "value": "59f7fba9e4b0edf0e25cd413"}, {"domain": ".processon.com", "expiry": 1555167313, "httpOnly": false, "name": "_gat", "path": "/", "secure": false, "value": "1"}, {"domain": ".processon.com", "expiry": 1555253657, "httpOnly": false, "name": "_gid", "path": "/", "secure": false, "value": "GA1.2.1345294219.1555167253"}, {"domain": ".processon.com", "expiry": 1618239257, "httpOnly": false, "name": "_ga", "path": "/", "secure": false, "value": "GA1.2.555498451.1555167253"}, {"domain": ".processon.com", "expiry": 1586703257, "httpOnly": false, "name": "zg_3f37ba50e54f4374b9af5be6d12b208f", "path": "/", "secure": false, "value": "%7B%22sid%22%3A%201555167253312%2C%22updated%22%3A%201555167257424%2C%22info%22%3A%201555167253326%2C%22superProperty%22%3A%20%22%7B%7D%22%2C%22platform%22%3A%20%22%7B%7D%22%2C%22utm%22%3A%20%22%7B%7D%22%2C%22referrerDomain%22%3A%20%22%22%2C%22cuid%22%3A%20%2259f7fba9e4b0edf0e25cd413%22%7D"}]

 

Cookie: zg_did=%7B%22did%22%3A%20%2216a16fc24ab1e7-08f589794c6e4d-7a1437-144000-16a16fc24ac76a%22%7D; _ga=GA1.2.1095343087.1555163784; _gid=GA1.2.545489346.1555163784; processon_userKey=59f7fba9e4b0edf0e25cd413; _sid=796afe66ce2a6002828ab3ca281f96fb; zg_3f37ba50e54f4374b9af5be6d12b208f=%7B%22sid%22%3A%201555163784372%2C%22updated%22%3A%201555165807015%2C%22info%22%3A%201555163784376%2C%22superProperty%22%3A%20%22%7B%7D%22%2C%22platform%22%3A%20%22%7B%7D%22%2C%22utm%22%3A%20%22%7B%7D%22%2C%22referrerDomain%22%3A%20%22%22%2C%22cuid%22%3A%20%2259f7fba9e4b0edf0e25cd413%22%7D; JSESSIONID=685AABAF6B8D70AF25E501C7E9E67A32.jvm1

 

參考連接:https://www.cnblogs.com/amou/p/9136925.html

     https://blog.csdn.net/eye_water/article/details/78484217

     https://blog.csdn.net/eye_water/article/details/78585394

     https://www.cnblogs.com/sticker0726/articles/10703682.html

 

原文出處:https://www.cnblogs.com/Summer-skr--blog/p/11403944.html

相關文章
相關標籤/搜索