在浏览网站的时候,有些网站需要登录,并且登录流程中有验证码验证。在爬虫中带验证的登录通常可以分为4各步骤:
1.获取登录页面:在登陆页面找到登录请求的url以及登录需要提交的参数
2.通过登录页找到验证码的url
3.处理验证码:包括下载验证码,识别验证码
4.发送登录请求:构造登录所需的所有参数进行登录请求
以上的步骤需要在一个session(会话)中进行,否则服务器不能识别验证码。验证码处理的方法一般包括手动处理、图像识别工具处理、云打码等,这次是用到的云打码。就是调用云打码这个网站的一个API将验证码图片传过去,然后获取的返回结果是识别后的验证码字符串。刚好云打码的登录页面需要验证码验证,就拿它做个练习。
获取登录页面
可以在首页看到登录的框,然后输入用户名密码,输入错误的验证码点击登录,在下面的控制台找到登录的请求,可以从请求中占到url,OMG,这里登录请求居然是get发送,而且用户名和密码都没有加密处理,神奇。
到验证码的url
跟上面类似的操作,刷新一下验证码可以在下面找到对应的获取验证码的请求,插葱header中拿到对应的验证码图片的url
处理验证码
接下来就是处理验证码了,需要用到云打码的一个接口,去他的网站上将Python对应的工具下载下来,备用。然后发送请求将验证码下载下来,调用接口将图片串过去获取返回的验证码。
发送登录请求
构造参数齐全的登录请求,从第一部中可以看到登录需要传递4各参数,username,password,utype,code
分别对应用户名、密码、用户类型、验证码。
最后请求返回结果:{"ret":0,"msg":"登录成功}
代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File : VerifyCodeDemo.py
# @Author: Small-orange
# @Date : 2020-1-9
# @Desc : 登录验证码破解
#步骤:1.找到登陆页面 2.获取验证码 3.处理验证码 4.发送登录请求
import requests
from fake_useragentimport UserAgent
from VerifiyCode.VerifyCodeUtilimport get_code
def parserCode(url,session):
# 获取验证码图片
filename ='verify_code.png' # 验证码图片的文件名
r = session.get(img_url,headers=headers)
if r.status_code ==200:
with open(filename,'wb')as f:#保存验证码图片
f.write(r.content)
vrify_code = get_code(filename)
return vrify_code
def login(url,vrify_code,session):
pass
#发送登录请求
params = {
"username":"small_orange",
"password":"small_orange",
"utype":"1",
"vcode":vrify_code
}
res = session.get(url,headers=headers,params=params)
if res.status_code ==200:
res.encoding ='utf-8'
print(res.text)
return res.text
if __name__ =='__main__':
img_url ='http://www.yundama.com/index/captcha'
url ='http://www.yundama.com/index/login'
ua = UserAgent()
headers = {'User-Agent':ua.chrome}
#获取session,保证获取验证码到登录在一个会话内完成
session = requests.session()
code = parserCode(img_url,session)
ret_text = login(url,code,session)
工具类
import http.client, mimetypes, urllib, json, time, requests
class YDMHttp:
apiurl ='http://api.yundama.com/api.php'
def __init__(self, username, password, appid, appkey):
self.username = username
self.password = password
self.appid =str(appid)
self.appkey = appkey
def request(self, fields, files=[]):
response =self.post_url(self.apiurl, fields, files)
response = json.loads(response)
return response
def balance(self):
data = {'method':'balance','username':self.username,'password':self.password,'appid':self.appid,'appkey':self.appkey}
response =self.request(data)
if (response):
if (response['ret']and response['ret'] <0):
return response['ret']
else:
return response['balance']
else:
return -9001
def login(self):
data = {'method':'login','username':self.username,'password':self.password,'appid':self.appid,'appkey':self.appkey}
response =self.request(data)
if (response):
if (response['ret']and response['ret'] <0):
return response['ret']
else:
return response['uid']
else:
return -9001
def upload(self, filename, codetype, timeout):
data = {'method':'upload','username':self.username,'password':self.password,'appid':self.appid,'appkey':self.appkey,'codetype':str(codetype),'timeout':str(timeout)}
file = {'file': filename}
response =self.request(data, file)
if (response):
if (response['ret']and response['ret'] <0):
return response['ret']
else:
return response['cid']
else:
return -9001
def result(self, cid):
data = {'method':'result','username':self.username,'password':self.password,'appid':self.appid,'appkey':self.appkey,'cid':str(cid)}
response =self.request(data)
return responseand response['text']or ''
def decode(self, filename, codetype, timeout):
cid =self.upload(filename, codetype, timeout)
if (cid >0):
for iin range(0, timeout):
result =self.result(cid)
if (result !=''):
return cid, result
else:
time.sleep(1)
return -3003,''
else:
return cid,''
def report(self, cid):
data = {'method':'report','username':self.username,'password':self.password,'appid':self.appid,'appkey':self.appkey,'cid':str(cid),'flag':'0'}
response =self.request(data)
if (response):
return response['ret']
else:
return -9001
def post_url(self, url, fields, files=[]):
for keyin files:
files[key] =open(files[key],'rb');
res = requests.post(url,files=files,data=fields)
return res.text
def get_code(filename):
# 用户名
username ='small_orange'
# 密码
password ='small_orange'
# 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
appid =9871
# 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
appkey ='f835940ba51bac771996d70df6531bce'
# 图片文件
filename = filename
# 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。在此查询所有类型http://www.yundama.com/price.html
codetype =1005
# 超时时间,秒
timeout =60
# 检查
if (username =='username'):
print('请设置好相关参数再测试')
else:
# 初始化
yundama = YDMHttp(username, password, appid, appkey)
# 登陆云打码
uid = yundama.login();
# 查询余额
balance = yundama.balance();
# 开始识别,图片路径,验证码类型ID,超时时间(秒),识别结果
cid, result = yundama.decode(filename, codetype, timeout);
print('cid: %s, result: %s' % (cid, result))
return result