ookie 用于存储 web 页面的用户信息。
什么是 Cookie?
Cookie 是一些数据, 存储于你电脑上的文本文件中。
当 web 服务器向浏览器发送 web 页面时,在连接关闭后,服务端不会记录用户的信息。
Cookie 的作用就是用于解决 "如何记录客户端的用户信息":
当用户访问 web 页面时,他的名字可以记录在 cookie 中。
在用户下一次访问该页面时,可以在 cookie 中读取用户访问记录。
Cookie 以名/值对形式存储,如下所示:
username=John Doe
当浏览器从服务器上请求 web 页面时, 属于该页面的 cookie 会被添加到该请求中。服务端通过这种方式来获取用户的信息。
使用 JavaScript 创建Cookie
JavaScript 可以使用 document.cookie 属性来创建 、读取、及删除 cookie。
JavaScript 中,创建 cookie 如下所示:
document.cookie="username=John Doe";
您还可以为 cookie 添加一个过期时间(以 UTC 或 GMT 时间)。默认情况下,cookie 在浏览器关闭时删除:
document.cookie="username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 GMT";
您可以使用 path 参数告诉浏览器 cookie 的路径。默认情况下,cookie 属于当前页面。
document.cookie="username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 GMT; path=/";
使用 JavaScript 读取 Cookie
在 JavaScript 中, 可以使用以下代码来读取 cookie:
var x = document.cookie;
使用 JavaScript 修改 Cookie
在 JavaScript 中,修改 cookie 类似于创建 cookie,如下所示:
document.cookie="username=John Smith; expires=Thu, 18 Dec 2013 12:00:00 GMT; path=/";
旧的 cookie 将被覆盖。
使用 JavaScript 删除 Cookie
删除 cookie 非常简单。您只需要设置 expires 参数为以前的时间即可,如下所示,设置为 Thu, 01 Jan 1970 00:00:00 GMT:
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
注意,当您删除时不必指定 cookie 的值。
Cookie 字符串
document.cookie 属性看起来像一个普通的文本字符串,其实它不是。
即使您在 document.cookie 中写入一个完整的 cookie 字符串, 当您重新读取该 cookie 信息时,cookie 信息是以名/值对的形式展示的。
如果您设置了新的 cookie,旧的 cookie 不会被覆盖。 新 cookie 将添加到 document.cookie 中,所以如果您重新读取document.cookie,您将获得如下所示的数据:
cookie1=value; cookie2=value;
显示所有 Cookie 创建 Cookie 1 创建 Cookie 2 删除 Cookie 1 删除 Cookie 2
如果您需要查找一个指定 cookie 值,您必须创建一个JavaScript 函数在 cookie 字符串中查找 cookie 值。
JavaScript Cookie 实例
在以下实例中,我们将创建 cookie 来存储访问者名称。
首先,访问者访问 web 页面, 他将被要求填写自己的名字。该名字会存储在 cookie 中。
访问者下一次访问页面时,他会看到一个欢迎的消息。
在这个实例中我们会创建 3 个 JavaScript 函数:
设置 cookie 值的函数
获取 cookie 值的函数
检测 cookie 值的函数
设置 cookie 值的函数
首先,我们创建一个函数用于存储访问者的名字:
function setCookie(cname,cvalue,exdays){
函数解析:
以上的函数参数中,cookie 的名称为 cname,cookie 的值为 cvalue,并设置了 cookie 的过期时间 expires。
该函数设置了 cookie 名、cookie 值、cookie过期时间。
获取 cookie 值的函数
然后,我们创建一个函数用户返回指定 cookie 的值:
function getCookie(cname){
函数解析:
cookie 名的参数为 cname。
创建一个文本变量用于检索指定 cookie :cname + "="。
使用分号来分割 document.cookie 字符串,并将分割后的字符串数组赋值给 ca (ca = document.cookie.split(';'))。
循环 ca 数组 (i=0;i<ca.length;i++),然后读取数组中的每个值,并去除前后空格 (c=ca[i].trim())。
如果找到 cookie(c.indexOf(name) == 0),返回 cookie 的值 (c.substring(name.length,c.length)。
如果没有找到 cookie, 返回 ""。
检测 cookie 值的函数
最后,我们可以创建一个检测 cookie 是否创建的函数。
如果设置了 cookie,将显示一个问候信息。
如果没有设置 cookie,将会显示一个弹窗用于询问访问者的名字,并调用 setCookie 函数将访问者的名字存储 365 天:
function checkCookie(){
完整实例
实例
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); }}}
以下实例在页面载入时执行 checkCookie() 函数。
document.cookie 将以字符串的方式返回所有的 cookie,类型格式: cookie1=value; cookie2=value; cookie3=value;
一节,我们使用Charles记录微博的登录过程,并从中解析出了微博的登录细节,还用Python模拟实现了整个过程。只要微博登录不改变,我们的代码就一直可用,这也算是一劳永逸的事情了,而且程序运行中不需要人工参与,高度自动化。记得之前微博还是有验证码的,这次重新实现的这个过程中没有发现验证码的蛛丝马迹。
完全用Python实现模拟登录的过程其实是很累的,考验的是耐力、观察力、联想能力等等。虽然累,但一旦完成后面就省心了,也算是值得一试。
然而世事无常,并非所有登录都像微博那样无验证码(也许有,只是没有跳出来),更多的是像12306,知乎,哔哩哔哩那样上了变态的验证码的。有时候为了自动识别验证码耗费的精力之大难以想象,所以我们写爬虫时,要综合考量投入产出比,人工输入验证码可能是更快捷便利的方法。
今天,我们就介绍一款专门从浏览器缓存的cookies获取cookies的工具,一个Python的模块:browsercookie。
它是一个很有用的爬虫工具,通过加载你浏览器的cookies到一个cookiejar对象里面,让你轻松下载需要登录的网页内容。
browsercookie 的安装
它的源代码在bitbucket上: browsercookie
可以从源码安装,或者直接pip安装
pip install browsercookie
需要注意的是,在Windows系统下,内置的sqlite模块在加载FireFox数据库时会抛出错误。需要更新sqlite的版本:
pip install pysqlite
我们拿百度的首页来做实验,如果没有登录cookies,打开的首页右上角菜单栏显示登录而不显示用户名,如果有登录cookies,首页则显示用户名而不显示登录,通过在得到的html中搜索“登录”来验证这两者的不同准备工作就是,要先打开浏览器(比如Chrome, 或Firefox)登录一下百度,然后就可以关掉浏览器了,当然开着也无所谓。
首先,我们看看未登录状态下得到的标题:
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
由上面的实验我们看出来,没有cookies请求得到登录的信息,‘user-name’是显示登录名时的css的class,通过查找user-name再次确认没有登录。
然后,在看看从浏览器获得cookies后得到的标题:
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
通过上面的代码,我们验证了从browsercookie获取cookies并成功登录的百度。
细心的小猿们可能已经发现了,我用的cookies是从Firefox那里得来的
<code>cjff = browsercookie.firefox()</code>。
原因是,我先实验从Chrome那里获取cookies,得到的cookies里面确实也包含百度,但是就是不能登录,于是改用Firefox就轻松登录了。
browsercookie 的缺憾
前面我们也提到了从Chrome获得的cookies不能登录百度的问题,后来我又实验了几个不同的网站,有的可以也有不可以的,再次证明了这个模块的不完美。
不过,这个库用起来很简单,几行代码就可以验证它对我们要登录的网站是否起作用,所以,写爬虫遇到登录的问题不妨先拿它验证一下,万一行呢,不就省了很多精力。
还有一类问题,就是你得到了cookies,访问任何该网站的URL,它都先返回一段登录验证的html,里面通过JS重定向到不同的网址,你需要进一步解析这段JS代码才能访问到你真正想访问的目标网址,这样的操作就比较累人,这样的网站对爬虫很不友好。别猜了,我说的就是微博。
<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>
这种异步加载的网页越来越多,尤其是前端框架ReactJS, VueJS等框架的出现让前后端分离,由浏览器运行JavaScript来渲染前端。这个时候,就需要我们的爬虫支持JavaScript的运行,此时此刻,requests等单纯的HTTP协议库已经无能为力了,我们需要更强大的工具
<!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名值对 var cookie=new Object(); for (var i=0;i<cookieArray.length;i++){ var arr=cookieArray[i].split("="); //将名和值分开 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){//获取指定名称的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){ //为时不设定过期时间,浏览器关闭时cookie自动消失 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)//两个参数,一个是cookie的名子,一个是值 { 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函数 { 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>
*请认真填写需求信息,我们会在24小时内与您取得联系。