1.整体分析
豆瓣的登陆界面
地址:https://accounts.douban.com/login
可以看到需要输入一个验证码
这个验证码是本次的一个难点
1.1 抓包,分析
首先手动登陆一次自己的账号,抓包
看到Form Data和Request Headers
Form Data
source:None
redir:https://www.douban.com/
form_email:jjhfen00@163.com
form_password:######## #此处为我的密码,隐去
captcha-solution:ticket
captcha-id:mS4q2fUVgP2fMlOHQYYy43qN:en
login:登录
分析:
- source、redir、login为不变的数据,模拟时直接用字符串写死就可以
- form_email、form_password为你的豆瓣账号和密码,手动输入或者写死都可以
- captcha-solution、captcha-id分别为验证码的值和验证码的id(服务器通过id判断是哪张验证码)
Request Headers
:host:accounts.douban.com
:method:POST
:path:/login
:scheme:https
:version:HTTP/1.1
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
accept-encoding:gzip, deflate
accept-language:zh-CN,zh;q=0.8
cache-control:max-age=0
content-length:201
content-type:application/x-www-form-urlencoded
cookie:########
origin:https://accounts.douban.com
referer:https://accounts.douban.com/login
upgrade-insecure-requests:1
user-agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
为了模拟实现豆瓣账号的登陆,我们需要模拟传输data和headers,就是把上面两个数据尽可能多地模拟,然后post给豆瓣服务器。
1.2 验证码获取
我们需要获取验证码的id和验证码图片的url,手动输入验证码存放到data中去。
到登陆页面的html文件中寻找id和url
打开审查元素,ctrl+shift+C,点击验证码图片,将会定位到相应的html结点。
<div>
<img id="captcha_image" src="https://www.douban.com/misc/captcha?id=hBZ8Xy8OJz8JxTANKxcjo383:en&size=s" alt="captcha" class="captcha_image">
<div class="captcha_block">
<span id="captcha_block" class="pl">请输入上图中的单词</span>
<input type="text" id="captcha_field" name="captcha-solution" tabindex="3" placeholder="验证码">
<input type="hidden" name="captcha-id" value="hBZ8Xy8OJz8JxTANKxcjo383:en">
</div>
</div>
从以上代码中可以看到验证码的id和url
id: hBZ8Xy8OJz8JxTANKxcjo383:en
url: https://www.douban.com/misc/captcha?id=hBZ8Xy8OJz8JxTANKxcjo383:en&size=s
1.3 程序分析
- 用requests库的session加载模拟的data和headers,post给豆瓣服务器,获取cookies
- 用BeautifulSoup找到验证码id和url所在的tag,并且获取id和url
2. 程序代码
# douban_login.py
import requests
from bs4 import BeautifulSoup
def _get_captcha(content):
"""
验证码获取函数,返回两个参数
:param content: 登录页面的html代码
:return: 验证码id, 验证码图片的url
"""
soup = BeautifulSoup(content)
captcha_id_tag = soup.find('input', attrs={'type':'hidden', 'name': 'captcha-id'})
captcha_image_tag = soup.find('img', attrs={'id': 'captcha_image', 'alt': 'captcha', 'class': 'captcha_image'})
return captcha_id_tag['value'], captcha_image_tag['src']
class DoubanClient(object):
def __init__(self):
object.__init__(self)
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36',
'origin': 'https://accounts.douban.com'
}
# create requests session
self.session = requests.Session()
self.session.headers.update(headers)
def login(self, username, password,
source='index_nav',
redir='https://www.douban.com/',
remember='on',
login='登录'):
"""
:param username: 用户名
:param password: 密码
:param source: 以下参数都是定死的字符串,抓包的时候查看
:param redir:
:param remember:
:param login:
"""
url = 'https://www.douban.com/accounts/login'
# 获取登录页面的内容,解析出验证码
r = requests.get(url)
(captcha_id, captha_url) = _get_captcha(r.content)
# 如果验证码解析正确,手动输入验证码
if captcha_id:
captcha_solution = input('please input the captcha for [%s]: ' % captha_url)
# 模拟data
data = {
'form_email': username,
'form_password': password,
'source': source,
'redir': redir,
'remember': remember,
'login': login
}
if captcha_id:
data['captcha-id'] = captcha_id
data['captcha-solution'] = captcha_solution
# 模拟headers
headers = {
'referer': 'https://accounts.douban.com/login?uid=&alias=&redir=https%3A%2F%2Fwww.douban.com%2F&source=index_nav&error=1001',
'host': 'accounts.douban.com'
}
# 向豆瓣服务器post,模拟豆瓣登录
r = self.session.post(url, data=data, headers=headers)
print(self.session.cookies.items())
def edit_signature(self, username, signature):
pass
if __name__ == '__main__':
c = DoubanClient()
c.login('jjhfen00@163.com', '密码才不给你们看!')