模拟登录过程的核心,是传送post请求时携带包含用户信息的参数(账号、密码、验证码),并且在整个爬取过程中,所有请求都要携带同一个cookie。
爬取的整个思路和步骤为:
请求网站登录路径,保存返回的cookie,并作为全局变量用于整个爬取过程
请求验证码,将识别后的文本保存下来
请求加密地址,通过AES加密过程获取密钥,并根据加密函数加密密码
发送包含登录名、加密密码、识别后验证码的post请求到登录地址
确认登录状态,如果成功则可以开始爬取数据
首先解决cookie初始化问题。通过cookielib和urllib2模块相结合来保证爬取过程中cookie的一致性,cookielib模块通过CookieJar类的对象来捕获cookie,建立存储cookie的对象cj,该对象只更新却不删除cookie,从而保证cookie自始至终一致。然后实例化一个全局opener,并绑定cookie库(即cj对象),此后opener发送请求和接受响应使用的cookie都会存在cj。最后安装opener对象。
import urllib2 import cookielib cj = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) urllib2.install_opener(opener)
需要注意,cj和opener都为全局变量,不能写在模块内部,这样整个爬取过程都能使用同一个cookie。初始化存放cookie的cj对象后,请求网站的登录路径,使用opener.open()将返回的cookie存入cj对象。
headers = {"User-Agent": "",
"Accept-Encoding": "gzip, deflate",
"Host": "",
"Referer": ""}
loginURL = ""
def receiveCookie():
requestLogin = urllib2.Request(loginURL, headers=headers)
responseLogin = opener.open(requestLogin)
receiveCookie()接下来是验证码的识别。由于爬取网站的验证码干扰项太多,用网上说的PIL包pytesseract包识别准确率仍然不理想,在工作任务要求时间紧张的情况下,我暂时选择了笨办法:获取验证码图像-->保存并弹出-->人工识别。由于始终爬取同一用户数据,且仅登录一次,因此只需要人工识别一次即可,以后有时间研究神经网络图像识别后再补充这部分吧。
import cStringIO
from PIL import Image
def receiveImage():
urlIm = ""
requestIm = urllib2.Request(urlIm, headers=headers)
responseIm = opener.open(requestIm)
fileIm = cStringIO.StringIO(responseIm.read())
img = Image.open(fileIm)
img.show()
receiveImage()
verify = raw_input("input verify:")由于一开始获得的cookie存入cj对象,因此之后所有的opener.open()命令都会携带该cookie,获得对应网址的响应。这里把验证码图片数据的读取内容通过cStringIO模块模拟成本地文件(实质是内存上的文件),可以像操作磁盘文件一样操作该文件。
其实一开始是直接使用urllib.urlretrieve()直接将验证码图片网址保存到本地后弹出,但是多次登录失败后发现这样写无法传递cookie,促使获得的验证码图片根本不是我们一开始登录时看到的图片,在保存图片的过程中实质又获得另一个cookie,因为cookie的不一致,网站无法保证两次行为是同一用户所为。而使用cStringIO模块前一步,刚好用opener携带了cookie。最终将弹出的图像肉眼识别后输入给verify变量。
最后是密码。爬取该网站时的一个大坑是密码是通过密钥加密的,通过fiddler捕获发现传递的post数据中password不是实际密码,
并且在输入各项用户参数后、登录成功前网站自动跳转到带有GetAESCode字样的路径并返回一串字母数字组成的密钥,这应该就是传说中的AES加密功能。
在登录页面调出控制台,password确实通过一个叫Encrypt()的函数加密,其加密原理是通过密钥code对实际密码进行转换。因此获得加密密码的整个过程拆分为:请求密钥路径-->获得密钥-->密码+密钥=加密后密码。最后一步可以将Encrypt函数的java代码转换成python格式写入py文件,也可以直接在控制台手动调用该函数,将结果传递给password变量。
def receiveCode():
urlCo = ""
requestCo = urllib2.Request(urlCo, headers=headers)
responseCo = opener.open(requestCo)
code = responseCo.read()
print “密钥:” + code
receiveCode()
password = raw_input("input pwd:")获得验证码、加密密码后算是大功告成,将三个参数传递给post请求,模拟登录。
def login():
dataList = {
"activity" : "login",
"userId": "",
"password": password,
"verifyCode": verify}
dataList = urllib.urlencode(dataList)
req = urllib2.Request(loginURL, dataList, headers)
res = opener.open(req)此时可以查看返回的响应是否为登录成功后实际看到的页面内容,如果是代表模拟登录成功,可以放心爬取任何内容了!
这是我第一次模拟登录如此复杂繁琐的网站,对于爬虫小白来说,对整个过程的理解和资料的搜集都比较困难,希望把这次经验好好记下,提醒自己温故知新,也希望能帮助更多的码农。
共同學習,寫下你的評論
評論加載中...
作者其他優質文章

