首页 > 代码库 > 用python模拟登录(解析cookie + 解析html + 表单提交 + 验证码识别 + excel读写 + 发送邮件)

用python模拟登录(解析cookie + 解析html + 表单提交 + 验证码识别 + excel读写 + 发送邮件)

    老婆大人每个月都要上一个网站上去查数据,然后做报表。

    为了减轻老婆大人的工作压力,所以我决定做个小程序,减轻我老婆的工作量。

 

准备工作

1.tesseract-ocr

    这个工具用来识别验证码,非常好用。

    ubuntu上安装:

sudo apt-get install tesseract-ocr

    非常简单。 

 

2.pytesseract和PIL(pillow)

    pytesseract用来在python中调用tesseract-ocr,PIL(pillow)用来加载图片,安装方法如下:

pip3 install pytesseractpip3 install pillow

    也非常简单。

    如果安装pillow的时候报如下错误:

ValueError: zlib is required unless explicitly disabled using --disable-zlib, aborting 

    那么我们更新一下pip即可

sudo pip3 install --upgrade pip

    如果pip速度很慢,可以改用国内的源,在命令后面加上 -i http://pypi.douban.com/simple (百度一下一大把),但pillow好像国内镜像都没有,只能用蜗牛速度从自带的源下载咯...

    一切准备就绪。

 

分析网站

    我们的目标网址是:http://222.217.19.16:3512/Site/LzsfySite/Default.aspx

 

    预览图:

技术分享

 

 

    看上去很low啊...心疼我老婆....看来我必须快点完成这个小程序了!

    经过简单的分析可以得到关键信息:

    1.表单的提交地址:http://222.217.19.16:3512/Site/LzsfySite/Default.aspx

    2.验证码地址:http://222.217.19.16:3512/Main/AspCode/ZhuChengXu/AuthenImage.aspx

    3.表单的格式:

 1 { 2             ‘__LASTFOCUS‘ : ‘‘, 3             ‘__EVENTTARGET‘ : ‘ctl00$ContentPlaceHolder1$Login1$btnLogin‘, 4             ‘__EVENTARGUMENT‘ : ‘‘, 5             ‘__VIEWSTATE‘ : __VIEWSTATE, 6             ‘__EVENTVALIDATION‘ : __EVENTVALIDATION, 7             ‘ctl00$ContentPlaceHolder1$Login1$txtUsr‘ : 用户名, 8             ‘ctl00$ContentPlaceHolder1$Login1$txtPwd‘ : 用户密码, 9             ‘ctl00$ContentPlaceHolder1$Login1$txtYZM‘ : 验证码10 }

        其中4、5、6行是访问首页的时候,在首页的源代码中返回的参数

技术分享

        但__EVENTARGUMENT常年为空,所以干脆直接写死空字符串即可;__VIEWSTATE和__EVENTVALIDATION则需要对html进行解析。

        7、8、9则对应用户名、密码和验证码,用户名密码可以写死,验证码则需要用到tesseract-ocr进行识别。

    4.表单提交的报文头

 1 { 2             ‘Accept‘ : b‘text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8‘, 3             ‘Accept-Encoding‘ : ‘gzip, deflate, lzma‘, 4             ‘Accept-Language‘ : ‘zh-CN,zh;q=0.8‘, 5             ‘Cache-Control‘ : ‘max-age=0‘, 6             ‘Connection‘ : ‘keep-alive‘, 7             ‘Content-Length‘ : 表单内容长度, 8             ‘Content-Type‘ : ‘application/x-www-form-urlencoded‘, 9             ‘Cookie‘ : cookie内容,10             ‘Host‘ : ‘222.217.19.16:3512‘,11             ‘Origin‘ : ‘http://222.217.19.16:3512‘,12             ‘Referer‘ : ‘http://222.217.19.16:3512/Site/LzsfySite/Default.aspx‘,13             ‘Upgrade-Insecure-Requests‘ : ‘1‘,14             ‘User-Agent‘ : ‘Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41}‘15 }

        其中7行可以根据构造的表单报问题长度来计算,9行需要从cookie中获取。

 

主要技术

获取cookie

    python3中获取cookie的方式很简单,用http.cookiejar。

    cookiejar扩展阅读:https://docs.python.org/3.0/library/http.cookiejar.html

import urllib.requestimport urllib.parseimport http.cookiejar#登录的主页面hosturl = http://222.217.19.16:3512/Site/LzsfySite/Default.aspx#设置一个cookie处理器,它负责从服务器下载cookie到本地,并且在发送请求时带上本地的cookiecj = http.cookiejar.LWPCookieJar()cookie_support = urllib.request.HTTPCookieProcessor(cj)opener = urllib.request.build_opener(cookie_support, urllib.request.HTTPHandler)urllib.request.install_opener(opener)#打开登录主页面(目的是从页面下载cookie,这样我们在再送post数据时就有cookie了,否则发送不成功)hostOpen = urllib.request.urlopen(hosturl)#解析cookiecookieText = ‘‘for item in cj:    cookieText = cookieText + item.name + = + item.value + &cookieText = cookieText[0:-1]print(cookieText)

    这样我们就可以得到cookie啦。

 

识别验证码

    这个也简单,我们先把它下载到本地,然后用pytesseract来解析它:

import urllib.requestimport pytesseractfrom PIL import Image#验证码图片地址checkCodeUrl = http://222.217.19.16:3512/Main/AspCode/ZhuChengXu/AuthenImage.aspx#下载验证码checkCodeOpen = urllib.request.urlopen(checkCodeUrl)data = checkCodeOpen.read()local = open(image.gif, wb)local.write(data)local.close()#pytesseract解析img = Image.open(image.gif)checkCode = pytesseract.image_to_string(img)print(checkCode)

    哈哈哈哈就这么简单暴力~

 

    诶等等!好像有点不对。我们多执行几次,然后对比一下输出和图片

    技术分享

      技术分享                ...出现了英文,什么鬼...再来

    

    技术分享        ...这次是正确的。再试试...

     技术分享                 又不对了。

 

    多试几次,发现验证码的识别率不太高。

    在识别率不高的情况下,那么我们只有开个循环,多识别几次验证码,然后多提交几次表单即可。——总有一次会正确滴~~

#以下是伪代码def 提交方法():    识别验证码    构造表单    提交表单    解析服务器返回报文        if 登录成功:        return true    else:        return falsewhile not 提交方法():    等待1000秒print(登录成功啦)

 

解析html 

我这里用的是python自带的HTMLParser,这种简单暴力的办法非常好用。   ^_^

from html.parser import HTMLParserimport urllib.request#主页面  hosturl = http://222.217.19.16:3512/Site/LzsfySite/Default.aspx#打开登录主页面hostOpen = urllib.request.urlopen(hosturl)#解析__VIEWSTATE和__EVENTVALIDATION#这里用了HTMLParser的库。#自定义的DefaultHTMLParser继承了HTMLParser#在调用此类型对象的feed方法对二进制字节流解析时,#若遇到tag的开始标签则会触发handle_starttag方法,#若遇到tag中的内容时则会触发handle_data方法class DefaultHTMLParser(HTMLParser):    def __init__(self):        HTMLParser.__init__(self)        self.hasLogin = False        #如果是input标签,则判断其id属性是否是__VIEWSTATE或__EVENTVALIDATION    #如果是二者之一,则在对象.xxxx属性中存入对应值    #这里假定一定能够从中读取到__VIEWSTATE和__EVENTVALIDATION    #没有做错误处理    def handle_starttag(self, tag, attrs):        iid = ‘‘        value = ‘‘        if tag == input:            for attr in attrs:                if attr[0] == id:                    iid = attr[1]                    break;            if iid in (__VIEWSTATE, __EVENTVALIDATION):                for attr in attrs:                    if attr[0] == value:                        exec(self. + iid + " = attr[1]")                                def handle_data(self, data):        #根据能否找到跳转语句判断是否登陆                if data.find(window.location=\‘../../Main/AspCode/ZhuChengXu/ShowSelect.aspx\‘) != -1:            self.hasLogin = True        #用eval装入各种属性    def get(self, attr):        result = eval(self. + attr)        return result                                p = DefaultHTMLParser()p.feed(hostOpen.read().decode(GB2312))print(p.get(__VIEWSTATE))print(p.get(__EVENTVALIDATION))

 

提交表单

根据之前的内容,我们已经获取了提交登录表单所需要的一切信息。

所以我们可以开始构造一个表单并提交

 1 import zlib 2 import urllib.request 3 import urllib.parse 4  5 #表单提交的url   6 hosturl = http://222.217.19.16:3512/Site/LzsfySite/Default.aspx 7  8 #构造表单 9 formData =http://www.mamicode.com/ {10     __LASTFOCUS : ‘‘,11     __EVENTTARGET : ctl00$ContentPlaceHolder1$Login1$btnLogin,12     __EVENTARGUMENT : ‘‘,13     __VIEWSTATE : __VIEWSTATE,14     __EVENTVALIDATION : __EVENTVALIDATION,15     ctl00$ContentPlaceHolder1$Login1$txtUsr : 用户名,16     ctl00$ContentPlaceHolder1$Login1$txtPwd : 密码,17     ctl00$ContentPlaceHolder1$Login1$txtYZM : xxxx18 }19 #对formData进行url编码20 formData =http://www.mamicode.com/ urllib.parse.urlencode(formData)21 22 #构造登陆用header23 headers = {24     Accept : btext/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8,25     Accept-Encoding : gzip, deflate, lzma,26     Accept-Language : zh-CN,zh;q=0.8,27     Cache-Control : max-age=0,28     Connection : keep-alive,29     Content-Length : len(formData.encode(GB2312)),30     Content-Type : application/x-www-form-urlencoded,31     Cookie : cookieText,32     Host : 222.217.19.16:3512,33     Origin : http://222.217.19.16:3512,34     Referer : http://222.217.19.16:3512/Site/LzsfySite/Default.aspx,35     Upgrade-Insecure-Requests : 1,36     User-Agent : Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41}37 }38 39 #开始登陆40 loginRequest = urllib.request.Request(hosturl, formData.encode(GB2312), headers)41 loginResponse = urllib.request.urlopen(loginRequest)42 #返回的数据是压缩过的,所以要用zlib进行解码43 loginResponseData = http://www.mamicode.com/zlib.decompress( loginResponse.read(), 16+zlib.MAX_WBITS).decode(GB2312)44 45 print(loginResponseData)

    需要注意的是,12-17行以及31行这里要填入前几节说明的解析的内容。否则服务器会返回500的响应码喔。

    上述内容基本上涵盖了做一个爬虫所需要的知识。

 

扩展内容

    但我的工作还没完,我还得给我老婆生成一个excel,并发送到她邮箱!

    所以,下面是关于写excel和发送email的扩展内容,不感兴趣的同学可以跳过啦。

快捷写入excel

    我们可以先手动做一个有标题,但内容为空的excel模板,像这样:

技术分享

 

技术分享

    注意,这里是第四个sheet。然后将其保存为empty.xls

 

    在这里我使用python的xlutils对此报表进行写入。(扩展阅读:http://xlutils.readthedocs.org/en/latest/)

    先安装。

sudo pip3 install xlutils

    简单示例:

 1 from xlutils.copy import copy 2 import xlrd 3 import xlwt 4 from xlwt.Style import easyxf 5  6  7 #打开文件,formatting_info=true表示读入单元格style信息 8 file = xlrd.open_workbook(empty.xls,formatting_info=True) 9 #用xlutils.copy的copy方法获取一个报表对象10 w = copy(file)11 12 #定义居中对齐格式示例13 alignment = xlwt.Alignment()14 alignment.horz = xlwt.Alignment.HORZ_CENTER15 style = xlwt.XFStyle()16 style.alignment = alignment17 18 #write方法的第一个参数对应要写入的行数,第二个参数对应要写入的列数,二者都是从0开始计算的19 #用居中对齐格式写入第3张sheet的3行7列单元格20 w.get_sheet(3).write(2,6, 2016 年 7 月 21 日至2016 年 8 月 20 日, style)21 #用居中对齐格式写入第3张sheet的16行3列单元格22 w.get_sheet(3).write(15,2, 2016 年 8 月 21 日 , style)23 24 #定义边框示例25 borders = xlwt.Borders()26 borders.left = 127 borders.right = 128 borders.top = 129 borders.bottom = 130 style = xlwt.XFStyle()31 style.borders = borders 32 style.alignment = alignment33 34 #填充数据35 for i in range(1, 18):36     w.get_sheet(3).write(9,i,int(100), style)37     w.get_sheet(3).write(10,i,int(100), style)38 39 40 #写入公式示例41 for i in range(1,18):42     column = chr(ord(A)+i)43     w.get_sheet(3).write(13, i, xlwt.Formula(SUM( + column + 10: + column + 13)),style)44 45 #保存为新文件46 w.save(报表.xls)

 

    然后我们就可以得到如下表格啦~~    python真的是非常简单又暴力...

技术分享

 

发送带有附件的email

这个更简单...smtplib在ubuntu下的python是自带的。

示例如下:

import smtplib  from email.mime.multipart import MIMEMultipart  from email.mime.text import MIMEText  from email.mime.application import MIMEApplication  print(准备邮件....)#qq邮箱用户名和密码,自带星号屏蔽#必须在账户设置开启smtp服务才能登录_user = "27*****68@qq.com"_pwd  = "***********"_to   = "10*****09@qq.com"  #初始化消息msg = MIMEMultipart()msg["Subject"] = "2016年9月份统计报表"msg["From"]= _user  msg["To"]  = _to  #这是文字部分part = MIMEText("详见附件...")  msg.attach(part)#这是附件部分  part = MIMEApplication(open(报表.xls,rb).read())  #filename最好设置成英文,否则容易出乱码part.add_header(Content-Disposition, attachment, filename="baobiao.xls")msg.attach(part)  #开始发送print(from  + _user +  to  + _to + ...)#必须要用SSL方式加密smtp = smtplib.SMTP_SSL(smtp.qq.com)smtp.login(_user, _pwd)smtp.sendmail(_user, _to, msg.as_string())smtp.quit()print(发送完毕)

 

    所做的一切都非常简单!所以python是世界上最好的语言!     笑....

    综合上述技术,删删改改增增减减,最后成果展示

技术分享

 

技术分享

 

    

    最后,感谢我老婆,让我有学习python的动力。

    本章完。

用python模拟登录(解析cookie + 解析html + 表单提交 + 验证码识别 + excel读写 + 发送邮件)