在我们爬取一些网站的时候,某些功能有可能需要登录,如果连续登录几次的话,会出现验证码,来达到分流或者反爬的效果
"上有政策,下有对策",网站使用验证码来阻止我们爬取内容,我们也有应对验证码的方法,这里我们使用的是云打码平台进行验证码的识别和验证
云打码网址 : http://www.yundama.com/about.html
①, 首先我们要注册账号,普通用户和开发者账号都要注册一下,注册完成之后,登录普通用户的账号,发现题分是0,但是我们测试是需要题分的呀!,可以联系客服,问客服能不能送点,一般是可以的,如果不可以的话,可以自己充值一块钱
②, 然后登录开发者账户,开始操作
③, 点击上方我的软件===>右上角添加新软件,添加一个软件,以便后边使用
④, 然后点击右侧的开发者中心,页面有教程,可以先下载例子查看一下
⑤, 我们使用的是python进行开发,所以下载的时候选择pythonHTTP示例下载
下载成功后的文件夹是这样的
⑥, 这里用的是python3,所以打开python3的文件
打开后可以看到里面是一个类,下面有用户名,密码,密钥,文件之类的信息,我们只需要根据注释,修改这些相关信息就可以了,其他的可以不用动,这样就可以进行验证码的识别了
# 用户名(云打码平台) username = 'username' # 密码(云打码平台) password = 'password' # 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得! appid = 1 # 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得! appkey = '22cc5376925e9387a23cf797cb9ba745' # 图片文件,从要爬取的页面获得 filename = 'getimage.jpg' # 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。在此查询所有类型 http://www.yundama.com/price.html codetype = 1004 # 超时时间,秒 timeout = 60
如果在爬取网页过程中使用的话,我们可以把上面的信息封装成一个函数,调用就可以了,不然每次都要写的话,会很麻烦,下面也会有相应的示例的:
- 人人网模拟登陆
云打码提供的代码(不需要修改):

1 import http.client, mimetypes, urllib, json, time, requests 2 3 4 ###################################################################### 5 6 class YDMHttp: 7 apiurl = 'http://api.yundama.com/api.php' 8 username = '' 9 password = '' 10 appid = '' 11 appkey = '' 12 13 def __init__(self, username, password, appid, appkey): 14 self.username = username 15 self.password = password 16 self.appid = str(appid) 17 self.appkey = appkey 18 19 def request(self, fields, files=[]): 20 response = self.post_url(self.apiurl, fields, files) 21 response = json.loads(response) 22 return response 23 24 def balance(self): 25 data = {'method': 'balance', 'username': self.username, 'password': self.password, 'appid': self.appid, 26 'appkey': self.appkey} 27 response = self.request(data) 28 if (response): 29 if (response['ret'] and response['ret'] < 0): 30 return response['ret'] 31 else: 32 return response['balance'] 33 else: 34 return -9001 35 36 def login(self): 37 data = {'method': 'login', 'username': self.username, 'password': self.password, 'appid': self.appid, 38 'appkey': self.appkey} 39 response = self.request(data) 40 if (response): 41 if (response['ret'] and response['ret'] < 0): 42 return response['ret'] 43 else: 44 return response['uid'] 45 else: 46 return -9001 47 48 def upload(self, filename, codetype, timeout): 49 data = {'method': 'upload', 'username': self.username, 'password': self.password, 'appid': self.appid, 50 'appkey': self.appkey, 'codetype': str(codetype), 'timeout': str(timeout)} 51 file = {'file': filename} 52 response = self.request(data, file) 53 if (response): 54 if (response['ret'] and response['ret'] < 0): 55 return response['ret'] 56 else: 57 return response['cid'] 58 else: 59 return -9001 60 61 def result(self, cid): 62 data = {'method': 'result', 'username': self.username, 'password': self.password, 'appid': self.appid, 63 'appkey': self.appkey, 'cid': str(cid)} 64 response = self.request(data) 65 return response and response['text'] or '' 66 67 def decode(self, filename, codetype, timeout): 68 cid = self.upload(filename, codetype, timeout) 69 if (cid > 0): 70 for i in range(0, timeout): 71 result = self.result(cid) 72 if (result != ''): 73 return cid, result 74 else: 75 time.sleep(1) 76 return -3003, '' 77 else: 78 return cid, '' 79 80 def report(self, cid): 81 data = {'method': 'report', 'username': self.username, 'password': self.password, 'appid': self.appid, 82 'appkey': self.appkey, 'cid': str(cid), 'flag': '0'} 83 response = self.request(data) 84 if (response): 85 return response['ret'] 86 else: 87 return -9001 88 89 def post_url(self, url, fields, files=[]): 90 for key in files: 91 files[key] = open(files[key], 'rb'); 92 res = requests.post(url, files=files, data=fields) 93 return res.text
云打码提供的代码,封装成函数,以便调用:

1 from 爬虫day03.YDM_YDMHttp import YDMHttp 2 3 4 def msg(username,password,img_path,codetype): 5 # 用户名(云打码平台) 6 username = username 7 8 # 密码(云打码平台) 9 password = password 10 11 # 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得! 12 appid = 1 13 14 # 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得! 15 appkey = '22cc5376925e9387a23cf797cb9ba745' 16 17 # 图片文件,从要爬取的页面获得 18 filename = img_path 19 20 # 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。在此查询所有类型 http://www.yundama.com/price.html 21 codetype = codetype 22 23 # 超时时间,秒 24 timeout = 10 25 26 # 检查 27 if (username == 'username'): 28 print('请设置好相关参数再测试') 29 else: 30 # 初始化 31 yundama = YDMHttp(username, password, appid, appkey) 32 33 # 登陆云打码 34 uid = yundama.login(); 35 #print('uid: %s' % uid) 36 37 # 查询余额 38 balance = yundama.balance(); 39 #print('balance: %s' % balance) 40 41 # 开始识别,图片路径,验证码类型ID,超时时间(秒),识别结果 42 cid, result = yundama.decode(filename, codetype, timeout); 43 print('cid: %s, result: %s' % (cid, result))
模拟人人网登录,保存登陆后的首页信息代码:
import requests import urllib from lxml import etree #导入之前封装好的函数 from YDM_msg import msg headers = { "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36" } url = "http://www.renren.com/SysHome.do" page_text = requests.get(url=url, headers=headers).text tree = etree.HTML(page_text)
#这里如果page_text里面对应的img标签里面的src不是完整的url的话,要自己复制图片链接,看看少了什么,自己拼接一下 img_url = tree.xpath("//*[@id='verifyPic_login']/@src")[0] urllib.request.urlretrieve(url=img_url,filename="code.jpg") #调用函数并传参 code_detail = msg("云打码用户名","云打码密码","./code.jpg",2004) login_url = "http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2019141546368" #获取session对象,登录成功后cookie会自动保存到session中,所以下面也直接用session发请求 session = requests.Session() #data里面是抓包工具抓到的信息,登录的时候需要携带的参数,
有一部分网站携带的参数是动态的,到页面右击检查,在页面搜索一下key,然后动态获取一下 data = { "email":"用户名", "icode":"", "origURL":"http://www.renren.com/home", "domain":"renren.com", "key_id":"1", "captcha_type":"web_login", "password":"密码密文", "rkey":"rkey", "f":"", } session.post(url=login_url,data=data,headers=headers) index_url = "http://www.renren.com/969892423" index_page_text = session.get(url=index_url,headers=headers).text with open("renren_index.html","w",encoding="utf-8") as f: f.write(index_page_text)
如果在运行过程中出现ssl的错误,有可能是抓包工具导致的,把抓包工具关掉就可以了,这里使用的抓包工具是fiddler4