<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title> New Document </title> <meta name="Generator" content="EditPlus"> <meta name="Author" content=""> <meta name="Keywords" content=""> <meta name="Description" content=""> </head> <body> <input type="text" id="a"/> <input type="button" value="保存cookie" onclick="test()"/> <input type="button" value="獲取cookie" onclick="alert(getCookie('userName'))"/> </body> <script language=javascript> window.onload=function(){ document.getElementById("a").value=getCookie('userName'); } function test() { var a=document.getElementById('a').value; SetCookie('userName',a) } //獲得coolie 的值 function cookie(name){ var cookieArray=document.cookie.split("; "); //得到分割的cookie名值對(duì) var cookie=new Object(); for (var i=0;i<cookieArray.length;i++){ var arr=cookieArray[i].split("="); //將名和值分開(kāi) if(arr[0]==name)return unescape(arr[1]); //如果是指定的cookie,則返回它的值 } return ""; } function delCookie(name)//刪除cookie { document.cookie=name+"=;expires="+(new Date(0)).toGMTString(); } function getCookie(objName){//獲取指定名稱(chēng)的cookie的值 var arrStr=document.cookie.split("; "); for(var i=0;i < arrStr.length;i ++){ var temp=arrStr[i].split("="); if(temp[0]==objName) return unescape(temp[1]); } } function addCookie(objName,objValue,objHours){ //添加cookie var str=objName + "=" + escape(objValue); if(objHours > 0){ //為時(shí)不設(shè)定過(guò)期時(shí)間,瀏覽器關(guān)閉時(shí)cookie自動(dòng)消失 var date=new Date(); var ms=objHours*3600*1000; date.setTime(date.getTime() + ms); str +="; expires=" + date.toGMTString(); } document.cookie=str; } function SetCookie(name,value)//兩個(gè)參數(shù),一個(gè)是cookie的名子,一個(gè)是值 { var Days=30; //此 cookie 將被保存 30 天 var exp=new Date(); //new Date("December 31, 9998"); exp.setTime(exp.getTime() + Days*24*60*60*1000); document.cookie=name + "="+ escape (value) + ";expires=" + exp.toGMTString(); } function getCookie(name)//取cookies函數(shù) { var arr=document.cookie.match(new RegExp("(^| )"+name+"=([^;]*)(;|$)")); if(arr !=null) return unescape(arr[2]); return null; } function delCookie(name)//刪除cookie { var exp=new Date(); exp.setTime(exp.getTime() - 1); var cval=getCookie(name); if(cval!=null) document.cookie=name + "="+cval+";expires="+exp.toGMTString(); } </script> </html>
ookie 用于存儲(chǔ) web 頁(yè)面的用戶(hù)信息。
什么是 Cookie?
Cookie 是一些數(shù)據(jù), 存儲(chǔ)于你電腦上的文本文件中。
當(dāng) web 服務(wù)器向?yàn)g覽器發(fā)送 web 頁(yè)面時(shí),在連接關(guān)閉后,服務(wù)端不會(huì)記錄用戶(hù)的信息。
Cookie 的作用就是用于解決 "如何記錄客戶(hù)端的用戶(hù)信息":
當(dāng)用戶(hù)訪(fǎng)問(wèn) web 頁(yè)面時(shí),他的名字可以記錄在 cookie 中。
在用戶(hù)下一次訪(fǎng)問(wèn)該頁(yè)面時(shí),可以在 cookie 中讀取用戶(hù)訪(fǎng)問(wèn)記錄。
Cookie 以名/值對(duì)形式存儲(chǔ),如下所示:
username=John Doe
當(dāng)瀏覽器從服務(wù)器上請(qǐng)求 web 頁(yè)面時(shí), 屬于該頁(yè)面的 cookie 會(huì)被添加到該請(qǐng)求中。服務(wù)端通過(guò)這種方式來(lái)獲取用戶(hù)的信息。
使用 JavaScript 創(chuàng)建Cookie
JavaScript 可以使用 document.cookie 屬性來(lái)創(chuàng)建 、讀取、及刪除 cookie。
JavaScript 中,創(chuàng)建 cookie 如下所示:
document.cookie="username=John Doe";
您還可以為 cookie 添加一個(gè)過(guò)期時(shí)間(以 UTC 或 GMT 時(shí)間)。默認(rèn)情況下,cookie 在瀏覽器關(guān)閉時(shí)刪除:
document.cookie="username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 GMT";
您可以使用 path 參數(shù)告訴瀏覽器 cookie 的路徑。默認(rèn)情況下,cookie 屬于當(dāng)前頁(yè)面。
document.cookie="username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 GMT; path=/";
使用 JavaScript 讀取 Cookie
在 JavaScript 中, 可以使用以下代碼來(lái)讀取 cookie:
var x=document.cookie;
使用 JavaScript 修改 Cookie
在 JavaScript 中,修改 cookie 類(lèi)似于創(chuàng)建 cookie,如下所示:
document.cookie="username=John Smith; expires=Thu, 18 Dec 2013 12:00:00 GMT; path=/";
舊的 cookie 將被覆蓋。
使用 JavaScript 刪除 Cookie
刪除 cookie 非常簡(jiǎn)單。您只需要設(shè)置 expires 參數(shù)為以前的時(shí)間即可,如下所示,設(shè)置為 Thu, 01 Jan 1970 00:00:00 GMT:
document.cookie="username=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
注意,當(dāng)您刪除時(shí)不必指定 cookie 的值。
Cookie 字符串
document.cookie 屬性看起來(lái)像一個(gè)普通的文本字符串,其實(shí)它不是。
即使您在 document.cookie 中寫(xiě)入一個(gè)完整的 cookie 字符串, 當(dāng)您重新讀取該 cookie 信息時(shí),cookie 信息是以名/值對(duì)的形式展示的。
如果您設(shè)置了新的 cookie,舊的 cookie 不會(huì)被覆蓋。 新 cookie 將添加到 document.cookie 中,所以如果您重新讀取document.cookie,您將獲得如下所示的數(shù)據(jù):
cookie1=value; cookie2=value;
顯示所有 Cookie 創(chuàng)建 Cookie 1 創(chuàng)建 Cookie 2 刪除 Cookie 1 刪除 Cookie 2
如果您需要查找一個(gè)指定 cookie 值,您必須創(chuàng)建一個(gè)JavaScript 函數(shù)在 cookie 字符串中查找 cookie 值。
JavaScript Cookie 實(shí)例
在以下實(shí)例中,我們將創(chuàng)建 cookie 來(lái)存儲(chǔ)訪(fǎng)問(wèn)者名稱(chēng)。
首先,訪(fǎng)問(wèn)者訪(fǎng)問(wèn) web 頁(yè)面, 他將被要求填寫(xiě)自己的名字。該名字會(huì)存儲(chǔ)在 cookie 中。
訪(fǎng)問(wèn)者下一次訪(fǎng)問(wèn)頁(yè)面時(shí),他會(huì)看到一個(gè)歡迎的消息。
在這個(gè)實(shí)例中我們會(huì)創(chuàng)建 3 個(gè) JavaScript 函數(shù):
設(shè)置 cookie 值的函數(shù)
獲取 cookie 值的函數(shù)
檢測(cè) cookie 值的函數(shù)
設(shè)置 cookie 值的函數(shù)
首先,我們創(chuàng)建一個(gè)函數(shù)用于存儲(chǔ)訪(fǎng)問(wèn)者的名字:
function setCookie(cname,cvalue,exdays){
函數(shù)解析:
以上的函數(shù)參數(shù)中,cookie 的名稱(chēng)為 cname,cookie 的值為 cvalue,并設(shè)置了 cookie 的過(guò)期時(shí)間 expires。
該函數(shù)設(shè)置了 cookie 名、cookie 值、cookie過(guò)期時(shí)間。
獲取 cookie 值的函數(shù)
然后,我們創(chuàng)建一個(gè)函數(shù)用戶(hù)返回指定 cookie 的值:
function getCookie(cname){
函數(shù)解析:
cookie 名的參數(shù)為 cname。
創(chuàng)建一個(gè)文本變量用于檢索指定 cookie :cname + "="。
使用分號(hào)來(lái)分割 document.cookie 字符串,并將分割后的字符串?dāng)?shù)組賦值給 ca (ca=document.cookie.split(';'))。
循環(huán) ca 數(shù)組 (i=0;i<ca.length;i++),然后讀取數(shù)組中的每個(gè)值,并去除前后空格 (c=ca[i].trim())。
如果找到 cookie(c.indexOf(name)==0),返回 cookie 的值 (c.substring(name.length,c.length)。
如果沒(méi)有找到 cookie, 返回 ""。
檢測(cè) cookie 值的函數(shù)
最后,我們可以創(chuàng)建一個(gè)檢測(cè) cookie 是否創(chuàng)建的函數(shù)。
如果設(shè)置了 cookie,將顯示一個(gè)問(wèn)候信息。
如果沒(méi)有設(shè)置 cookie,將會(huì)顯示一個(gè)彈窗用于詢(xún)問(wèn)訪(fǎng)問(wèn)者的名字,并調(diào)用 setCookie 函數(shù)將訪(fǎng)問(wèn)者的名字存儲(chǔ) 365 天:
function checkCookie(){
完整實(shí)例
實(shí)例
functionsetCookie(cname,cvalue,exdays){vard=newDate(); d.setTime(d.getTime()+(exdays*24*60*60*1000)); varexpires="expires="+d.toGMTString(); document.cookie=cname + "=" + cvalue + "; " + expires;}functiongetCookie(cname){varname=cname + "="; varca=document.cookie.split(';'); for(vari=0; i<ca.length; i++){varc=ca[i].trim(); if(c.indexOf(name)==0)returnc.substring(name.length,c.length); }return"";}functioncheckCookie(){varuser=getCookie("username"); if(user!=""){alert("Welcome again " + user); }else{user=prompt("Please enter your name:",""); if(user!="" && user!=null){setCookie("username",user,365); }}}
以下實(shí)例在頁(yè)面載入時(shí)執(zhí)行 checkCookie() 函數(shù)。
document.cookie 將以字符串的方式返回所有的 cookie,類(lèi)型格式: cookie1=value; cookie2=value; cookie3=value;
一節(jié),我們使用Charles記錄微博的登錄過(guò)程,并從中解析出了微博的登錄細(xì)節(jié),還用Python模擬實(shí)現(xiàn)了整個(gè)過(guò)程。只要微博登錄不改變,我們的代碼就一直可用,這也算是一勞永逸的事情了,而且程序運(yùn)行中不需要人工參與,高度自動(dòng)化。記得之前微博還是有驗(yàn)證碼的,這次重新實(shí)現(xiàn)的這個(gè)過(guò)程中沒(méi)有發(fā)現(xiàn)驗(yàn)證碼的蛛絲馬跡。
完全用Python實(shí)現(xiàn)模擬登錄的過(guò)程其實(shí)是很累的,考驗(yàn)的是耐力、觀(guān)察力、聯(lián)想能力等等。雖然累,但一旦完成后面就省心了,也算是值得一試。
然而世事無(wú)常,并非所有登錄都像微博那樣無(wú)驗(yàn)證碼(也許有,只是沒(méi)有跳出來(lái)),更多的是像12306,知乎,嗶哩嗶哩那樣上了變態(tài)的驗(yàn)證碼的。有時(shí)候?yàn)榱俗詣?dòng)識(shí)別驗(yàn)證碼耗費(fèi)的精力之大難以想象,所以我們寫(xiě)爬蟲(chóng)時(shí),要綜合考量投入產(chǎn)出比,人工輸入驗(yàn)證碼可能是更快捷便利的方法。
今天,我們就介紹一款專(zhuān)門(mén)從瀏覽器緩存的cookies獲取cookies的工具,一個(gè)Python的模塊:browsercookie。
它是一個(gè)很有用的爬蟲(chóng)工具,通過(guò)加載你瀏覽器的cookies到一個(gè)cookiejar對(duì)象里面,讓你輕松下載需要登錄的網(wǎng)頁(yè)內(nèi)容。
browsercookie 的安裝
它的源代碼在bitbucket上: browsercookie
可以從源碼安裝,或者直接pip安裝
pip install browsercookie
需要注意的是,在Windows系統(tǒng)下,內(nèi)置的sqlite模塊在加載FireFox數(shù)據(jù)庫(kù)時(shí)會(huì)拋出錯(cuò)誤。需要更新sqlite的版本:
pip install pysqlite
我們拿百度的首頁(yè)來(lái)做實(shí)驗(yàn),如果沒(méi)有登錄cookies,打開(kāi)的首頁(yè)右上角菜單欄顯示登錄而不顯示用戶(hù)名,如果有登錄cookies,首頁(yè)則顯示用戶(hù)名而不顯示登錄,通過(guò)在得到的html中搜索“登錄”來(lái)驗(yàn)證這兩者的不同準(zhǔn)備工作就是,要先打開(kāi)瀏覽器(比如Chrome, 或Firefox)登錄一下百度,然后就可以關(guān)掉瀏覽器了,當(dāng)然開(kāi)著也無(wú)所謂。
首先,我們看看未登錄狀態(tài)下得到的標(biāo)題:
In [1]: import requests In [2]: url='https://baidu.com/' In [3]: r1=requests.get(url) In [4]: r1.content.decode('utf-8').find('登錄') Out[4]: 1580 In [5]: r1.content.decode('utf8').find('user-name') Out[5]: -1
由上面的實(shí)驗(yàn)我們看出來(lái),沒(méi)有cookies請(qǐng)求得到登錄的信息,‘user-name’是顯示登錄名時(shí)的css的class,通過(guò)查找user-name再次確認(rèn)沒(méi)有登錄。
然后,在看看從瀏覽器獲得cookies后得到的標(biāo)題:
In [11]: cjff=browsercookie.firefox() In [12]: header={'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36'} In [13]: r2=requests.get(url, cookies=cjff, headers=header) In [14]: r2.content.decode('utf8').find('登錄') Out[14]: -1 In [15]: r2.content.decode('utf8').find('user-name') Out[15]: 5038
通過(guò)上面的代碼,我們驗(yàn)證了從browsercookie獲取cookies并成功登錄的百度。
細(xì)心的小猿們可能已經(jīng)發(fā)現(xiàn)了,我用的cookies是從Firefox那里得來(lái)的
<code>cjff=browsercookie.firefox()</code>。
原因是,我先實(shí)驗(yàn)從Chrome那里獲取cookies,得到的cookies里面確實(shí)也包含百度,但是就是不能登錄,于是改用Firefox就輕松登錄了。
browsercookie 的缺憾
前面我們也提到了從Chrome獲得的cookies不能登錄百度的問(wèn)題,后來(lái)我又實(shí)驗(yàn)了幾個(gè)不同的網(wǎng)站,有的可以也有不可以的,再次證明了這個(gè)模塊的不完美。
不過(guò),這個(gè)庫(kù)用起來(lái)很簡(jiǎn)單,幾行代碼就可以驗(yàn)證它對(duì)我們要登錄的網(wǎng)站是否起作用,所以,寫(xiě)爬蟲(chóng)遇到登錄的問(wèn)題不妨先拿它驗(yàn)證一下,萬(wàn)一行呢,不就省了很多精力。
還有一類(lèi)問(wèn)題,就是你得到了cookies,訪(fǎng)問(wèn)任何該網(wǎng)站的URL,它都先返回一段登錄驗(yàn)證的html,里面通過(guò)JS重定向到不同的網(wǎng)址,你需要進(jìn)一步解析這段JS代碼才能訪(fǎng)問(wèn)到你真正想訪(fǎng)問(wèn)的目標(biāo)網(wǎng)址,這樣的操作就比較累人,這樣的網(wǎng)站對(duì)爬蟲(chóng)很不友好。別猜了,我說(shuō)的就是微博。
<html> <head> <title>新浪通行證</title> <meta http-equiv="refresh" content="0; url='https://login.sina.com.cn/crossdomain2.php?action=login&entry=miniblog&r=https%3A%2F%2Fpassport.weibo.com%2Fwbsso%2Flogin%3Fssosavestate%3D1574046135%26url%3Dhttps%253A%252F%252Fweibo.com%252Fkaifulee%26display%3D0%26ticket%3DST-MTM3MTQ1MzA0MA%3D%3D-1542510135-gz-E235393C87F25EE4E30B221C2B5F7F37-1%26retcode%3D0&login_time=1542509978&sign=d531a8b4eed9c403'"/> <meta http-equiv="Content-Type" content="text/html; charset=GBK" /> </head> <body bgcolor="#ffffff" text="#000000" link="#0000cc" vlink="#551a8b" alink="#ff0000"> <script type="text/javascript" language="javascript"> location.replace("https://login.sina.com.cn/crossdomain2.php?action=login&entry=miniblog&r=https%3A%2F%2Fpassport.weibo.com%2Fwbsso%2Flogin%3Fssosavestate%3D1574046135%26url%3Dhttps%253A%252F%252Fweibo.com%252Fkaifulee%26display%3D0%26ticket%3DST-MTM3MTQ1MzA0MA%3D%3D-1542510135-gz-E235393C87F25EE4E30B221C2B5F7F37-1%26retcode%3D0&login_time=1542509978&sign=d531a8b4eed9c403"); </script> </body> </html>
這種異步加載的網(wǎng)頁(yè)越來(lái)越多,尤其是前端框架ReactJS, VueJS等框架的出現(xiàn)讓前后端分離,由瀏覽器運(yùn)行JavaScript來(lái)渲染前端。這個(gè)時(shí)候,就需要我們的爬蟲(chóng)支持JavaScript的運(yùn)行,此時(shí)此刻,requests等單純的HTTP協(xié)議庫(kù)已經(jīng)無(wú)能為力了,我們需要更強(qiáng)大的工具
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。