做者:xiaoyuhtml
微信公众号:Python数据科学git
知乎:Python数据分析师github
前两篇和你们分享了爬虫中http的一些概念和使用方法,基础篇咱们主要介绍了http的请求头
,高级篇咱们主要介绍了cookie
和session
(具体能够点击上面连接进行回顾)。但其实在爬虫中还有不少关于http的内容须要了解,例如 token
,oauth
等。对于这些概念博主将在后续文章中逐一的详细介绍,本篇主要针对前两篇内容与你们分享一个模拟登陆
的实战例子。算法
开始想以知乎为例,可是看到网上关于知乎模拟登陆的教程太多了,因此就以“京东”
为例。api
你们都知道,京东是不须要登陆就能够访问主页内容的,所以模拟登陆的意义在于查看我的信息,好比能够获取我的的交易信息(购物车商品,购物历史记录,待收货商品信息等),或者卖家的商品销售信息和评论等等。浏览器
好了,了解背景事后,让咱们开始模拟登陆吧。安全
你们都知道,模拟登陆其实就是经过http的post请求
方式来提交用户信息的(用户名和密码
)。对于浏览器而言,只输入用户名和密码就能够登录了(偶尔有验证码),那是由于浏览器在背后都帮你处理好了。而爬虫的模拟登陆过程须要咱们本身解决,所以咱们须要弄清楚浏览器的那些背后操做是如何进行的才能对症下药。bash
难点分析:服务器
咱们打开浏览器,博主用的Chrome
浏览器。首先使用Ctrl+Shift+N
进入干净的无痕模式,防止以前的cookie数据形成干扰。微信
输入了京东的登录网址 passport.jd.com/new/login.a…,进入以下登陆界面。
如今咱们经过开发者工具来看看浏览器背后都干了什么吧。有的朋友提问到,输入用户名和密码后页面直接跳转到主页面了,看不到咱们要的数据了。其实这里只须要故意将你的密码输错不进入跳转就能够解决了。
点击登陆,而后咱们看到有个FormData
,这就是浏览器每次向服务器提交的表单信息。
第一眼看过去感受快要无望了。可是别着急,这些字段信息其实都是有处可寻的。咱们Ctrl+U
打开京东登陆页面的源码里,而后Ctrl+F
试着搜一搜这些字段信息。
先搜第一个uuid
字段,发现它就在源码中,紧着后面是一些其它的字段信息,那就齐活了。咱们看到除了loginname,nloginpwd,authcode,
其余的字段全都是hidden
的类型,也就是被隐藏
了的字段。
好了,那下一步就天然知道干什么了。咱们能够直接请求登陆页面源码提取字段信息了。
Cookie能够经过使用http的Cookiejar
定制opener
进行获取,也能够直接使用requests
模块来实现。
requests模块实现起来比较方便,由于内部已经封装好了自动处理Cookie的功能。第一次发送请求能够经过服务器获取Cookie,后续的请求则会自动带着已获取的Cookie信息进行发送。固然,也能够手动添加Cookie,手动添加的Cookie优先级高,将会覆盖默认的信息。
为了说明模拟登陆的用法,本篇博主将使用简便的requests模块来完成对Cookie的处理。
验证码的处理方法也有多种,能够分为自动识别
的和手动识别
。
OCR
智能图文识别,机器学习
进行识别训练等。本篇将选择手动录入验证码,旨在理解模拟登陆的过程。
class JD_crawl:
def __init__(self, username, password):
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36'
' (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
'Referer': 'https://www.jd.com/',
}
self.login_url = "https://passport.jd.com/new/login.aspx"
self.post_url = "https://passport.jd.com/uc/loginService"
self.auth_url = "https://passport.jd.com/uc/showAuthCode"
self.session = requests.session()
self.username = username
self.password = password
复制代码
JD_crawl
的类,设置了实例的headers
和session
会话对象,以及三个后面请求须要用到的url。session会话对象
。def get_login_info(self):
html = self.session.get(self.login_url, headers=self.headers).content
soup = BeautifulSoup(html, 'lxml')
uuid = soup.select('#uuid')[0].get('value')
eid = soup.select('#eid')[0].get('value')
fp = soup.select('input[name="fp"]')[0].get('value') # session id
_t = soup.select('input[name="_t"]')[0].get('value') # token
login_type = soup.select('input[name="loginType"]')[0].get('value')
pub_key = soup.select('input[name="pubKey"]')[0].get('value')
sa_token = soup.select('input[name="sa_token"]')[0].get('value')
auth_page = self.session.post(self.auth_url,
data={'loginName': self.username, 'nloginpwd': self.password}).text
print(auth_page)
if 'true' in auth_page:
auth_code_url = soup.select('#JD_Verification1')[0].get('src2')
auth_code = str(self.get_auth_img(auth_code_url))
else:
auth_code = ''
data = {
'uuid': uuid,
'eid': eid,
'fp': fp,
'_t': _t,
'loginType': login_type,
'loginname': self.username,
'nloginpwd': self.password,
'chkRememberMe': True,
'pubKey': pub_key,
'sa_token': sa_token,
'authcode': auth_code
}
return data
复制代码
login_url
发起请求,获取登录页面源码后经过BeautifulSoup
解析工具ccs选择器
来提取隐藏字段信息。loginname,nloginpwd,authcode
三个非隐藏字段须要用户手动录入。https://passport.jd.com/uc/showAuthCode
(代码中的auth_url)来判断。请求结果是一个以下格式的字符串。
请求结果: ({"verifycode":xxx})
xxx:true 或者 false
复制代码
所以能够简单的查看结果中是否有true
来判断是否须要验证码。
true
就须要调用验证码函数方法,将验证码图片下载,输入图片上的验证码,并赋给authcode
字段进行表单提交完成登陆。authcode
字段为空字符串。通常当咱们屡次输入了错误的帐号或密码时,构成安全危险,就会提示输入验证码。
def get_auth_img(self, url):
auth_code_url = 'http:{}&yys={}'.format(url, str(int(time.time()*1000)))
auth_img = self.session.get(auth_code_url, headers=self.headers)
with open('authcode.jpg', 'wb') as f:
f.write(auth_img.content)
code_typein = input('请根据下载图片输入验证码:')
return code_typein
复制代码
src2
src2="//authcode.jd.com/verify/image?a=1&acid=dcb4370b-2763-44e6-83ff-4b89bc01193d&uid=dcb4370b-2763-44e6-83ff-4b89bc01193d"
复制代码
所以,咱们须要将它补全,在src2
前面拼接字符串 http:
。可是当咱们尝试这个url的时候会发现图片并无下载成功,为何呢?
由于还须要在结尾加上时间戳,接着看后边的 onclic
k,它的字符串中有和src2
彻底同样的连接,但在结尾处多了 &yys= ''
。经过观察内容发现有 date
和 time
字样,因而能够判断这多是一个时间戳字符串
。
onclick="this.src= document.location.protocol +'//authcode.jd.com/verify/image?a=1&acid=dcb4370b-2763-44e6-83ff-4b89bc01193d&uid=dcb4370b-2763-44e6-83ff-4b89bc01193d&yys='+new Date().getTime();$('#authcode').val('');"
复制代码
小提示:
时间戳(引自百度百科):
时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至如今的总秒数。
时间戳在Python中能够用time模块
来完成:
time.time()*1000
复制代码
jpg
格式,储存在项目文件目录下。能够看到图片就在目录下,咱们双击打开而后按照图片输入验证码。
def login(self):
data = self.get_login_info()
headers = {
'Referer': self.post_url,
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36'
' (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
}
try:
login_page = self.session.post(self.post_url, data=data, headers=headers)
print(login_page.text)
except Exception as e:
print(e)
复制代码
https://passport.jd.com/uc/loginService
"S"
是大写。若是登陆成功,则会显示如下字符串。
({"success":"http://www.jd.com"})
复制代码
为了验证登陆真的成功了,现将博主的购物车拿出来作实验,若是在获取源码中找到了指定商品名称,那么就说明成功了。
好吧,都是以前随便放的,就以牙线
为测试目标吧。
def shopping(self):
carshop = self.session.post('https://cart.jd.com/cart.action', headers=self.headers)
print(carshop.text)
复制代码
简单的请求了一下购物车url
。在下载的源码中搜索“牙”
,而后找了目标。
本篇主要介绍了京东商城的模拟登陆方法,固然还有一些网站的登陆机制比较复杂,好比weibo
登陆须要调用api
,须要咱们详细阅读api说明。
后续将会分享更多模拟登陆的内容,欢迎你们指正。
参考连接: https://github.com/xchaoinfo/fuck-login http://blog.csdn.net/weixin_38206454/article/details/78655209?locationNum=2&fps=1
关注微信公众号Python数据科学,获取 120G
人工智能 学习资料。