⽤python模拟登录(解析cookie+解析html+表单提交+验证码识
别+excel读。。。
⽼婆⼤⼈每个⽉都要上⼀个⽹站上去查数据,然后做报表。
为了减轻⽼婆⼤⼈的⼯作压⼒,所以我决定做个⼩程序,减轻我⽼婆的⼯作量。
准备⼯作
这个⼯具⽤来识别验证码,⾮常好⽤。
ubuntu上安装:
sudo apt-get install tesseract-ocr
⾮常简单。
2.pytesseract和PIL(pillow)
pytesseract⽤来在python中调⽤tesseract-ocr,PIL(pillow)⽤来加载图⽚,安装⽅法如下:
pip3 install pytesseract
pip3 install pillow
也⾮常简单。
如果安装pillow的时候报如下错误:
ValueError: zlib is required unless explicitly disabled using --disable-zlib, aborting
那么我们更新⼀下pip即可
sudo pip3 install --upgrade pip
⼀切准备就绪。
分析⽹站
预览图:
看上去很low啊...⼼疼我⽼婆....看来我必须快点完成这个⼩程序了!
经过简单的分析可以得到关键信息:
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' : '222.217.19.16:3512',
12            'Referer' : '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的⽅式很简单,⽤kiejar。
quest
import urllib.parse
kiejar
#登录的主页⾯
hosturl = '222.217.19.16:3512/Site/LzsfySite/Default.aspx'
#设置⼀个cookie处理器,它负责从服务器下载cookie到本地,并且在发送请求时带上本地的cookie
cj = kiejar.LWPCookieJar()
cookie_support = quest.HTTPCookieProcessor(cj)
opener = quest.build_opener(cookie_support, quest.HTTPHandler)
#打开登录主页⾯(⽬的是从页⾯下载cookie,这样我们在再送post数据时就有cookie了,否则发送不成功)
hostOpen = quest.urlopen(hosturl)
#解析cookie
cookieText = ''
for item in cj:
cookieText = cookieText + item.name + '=' + item.value + '&'
cookieText = cookieText[0:-1]
print(cookieText)
这样我们就可以得到cookie啦。
识别验证码
这个也简单,我们先把它下载到本地,然后⽤pytesseract来解析它:
quest
import pytesseract
from PIL import Image
#验证码图⽚地址
checkCodeUrl = '222.217.19.16:3512/Main/AspCode/ZhuChengXu/AuthenImage.aspx'
#下载验证码
checkCodeOpen = quest.urlopen(checkCodeUrl)
data = ad()
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 false
while not提交⽅法():
等待1000秒
print('登录成功啦')
解析html
我这⾥⽤的是python⾃带的HTMLParser,这种简单暴⼒的办法⾮常好⽤。  ^_^
from html.parser import HTMLParser
quest
#主页⾯
hosturl = '222.217.19.16:3512/Site/LzsfySite/Default.aspx'
#打开登录主页⾯
hostOpen = quest.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]
selenium获取cookiebreak;
#⽤exec来设置属性值,节省代码量^_^
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
#get⽅法,⽤来获取属性值。
#这⾥偷懒⽤了eval——eval的效率不太⾼,但⾮常省代码量。
#如果对执⾏速度要求⽐较⾼建议不要⽤这个⽅法喔。
def get(self, attr):
result = eval('self.' + attr)
return result
p = DefaultHTMLParser()
p.ad().decode('GB2312'))
('__VIEWSTATE'))
('__EVENTVALIDATION'))
提交表单
根据之前的内容,我们已经获取了提交登录表单所需要的⼀切信息。
所以我们可以开始构造⼀个表单并提交
1import zlib
quest
3import urllib.parse
4
5#表单提交的url
6 hosturl = '222.217.19.16:3512/Site/LzsfySite/Default.aspx'
7
8#构造表单
9 formData = {
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' : 'xxxx'
18 }
19#对formData进⾏url编码
20 formData = urllib.parse.urlencode(formData)
21
22#构造登陆⽤header
23 headers = {
24'Accept' : b'text/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' : de('GB2312')),
30'Content-Type' : 'application/x-www-form-urlencoded',
31'Cookie' : 'cookieText',
32'Host' : '222.217.19.16:3512',
33'Origin' : '222.217.19.16:3512',
34'Referer' : '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 = quest.Request(hosturl, de('GB2312'), headers)
41 loginResponse = quest.urlopen(loginRequest)
42#返回的数据是压缩过的,所以要⽤zlib进⾏解码
43 loginResponseData = zlib.decompress( ad(), 16+zlib.MAX_WBITS).decode('GB2312')
44
45print(loginResponseData)
需要注意的是,12-17⾏以及31⾏这⾥要填⼊前⼏节说明的解析的内容。否则服务器会返回500的响应码喔。
上述内容基本上涵盖了做⼀个爬⾍所需要的知识。
扩展内容
但我的⼯作还没完,我还得给我⽼婆⽣成⼀个excel,并发送到她邮箱!
所以,下⾯是关于写excel和发送email的扩展内容,不感兴趣的同学可以跳过啦。快捷写⼊excel
我们可以先⼿动做⼀个有标题,但内容为空的excel模板,像这样:
注意,这⾥是第四个sheet。然后将其保存为empty.xls
先安装。
sudo pip3 install xlutils
简单⽰例:
py import copy
2import xlrd
3import xlwt
4from xlwt.Style import easyxf
5
6
7#打开⽂件,formatting_info=true表⽰读⼊单元格style信息
8 file = xlrd.open_workbook('empty.xls',formatting_info=True)
9#⽤py的copy⽅法获取⼀个报表对象
10 w = copy(file)
11
12#定义居中对齐格式⽰例
13 alignment = xlwt.Alignment()
14 alignment.horz = xlwt.Alignment.HORZ_CENTER
15 style = xlwt.XFStyle()
16 style.alignment = alignment
17
18#write⽅法的第⼀个参数对应要写⼊的⾏数,第⼆个参数对应要写⼊的列数,⼆者都是从0开始计算的19#⽤居中对齐格式写⼊第3张sheet的3⾏7列单元格
_sheet(3).write(2,6, '2016 年 7 ⽉ 21 ⽇⾄2016 年 8 ⽉ 20 ⽇', style)
21#⽤居中对齐格式写⼊第3张sheet的16⾏3列单元格
_sheet(3).write(15,2, '2016 年 8 ⽉ 21 ⽇' , style)
23
24#定义边框⽰例
25 borders = xlwt.Borders()
26 borders.left = 1
27 borders.right = 1
p = 1
29 borders.bottom = 1
30 style = xlwt.XFStyle()
31 style.borders = borders
32 style.alignment = alignment
33
34#填充数据
35for 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#写⼊公式⽰例
41for 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真的是⾮常简单⼜暴⼒...

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。