月度归档:2017年07月

一个Python抢课脚本

如果没有过抢课的经历可以说是白读四年大学了,每次抢课玩的就是速度与激情,最近在学Python爬虫相关,正好可以当一次实战练习,这次使用Python标准库中的urllib与urllib2,其带有http的服务器端和客户端的应用支持。

折腾前准备

Python2.7
Chrome中的开发者工具

有人说Python 2和Python 3是两门完全不同的语言,关于Python版本之争就不多说了,反正萝卜白菜各有所爱,由于关于Python3的教程太少所以我就选2.7了

Firefox的Firebug也是一个很不错的调试工具。

首先需要了解基本的Python语法,HTTP请求(post,get),详细教程请移步这里

模拟登录

首先贴出学校选课系统的主页(几年前的iframe嵌套风格,前端逼格太low没办法)

选课主页

模拟登录是爬虫的里面很重要的一个环节。模拟登录一个站点时,首先要弄清网站的登录处理细节(内容,目的地...),这里通过Chrome开发者工具来抓取http数据包来分析该网站的登录流程。除此之外,我们还要分析抓到的post包的数据结构和header,要根据提交的数据结构和heander来构造自己的post数据和header。

我们要构造自己的HTTP数据包,并发送给指定url。我们通过urllib2等几个模块来实现request请求的发送和相应的接收。大部分网站登录时需要携带cookie,所以我们还必须设置cookie处理器来保证cookie。

这里我通过两种方法实现模拟登录,手动输入和cookie。

手动输入

这里先手动输入学号,密码和验证码进行模拟登陆。

点击登录,弹出输入框。

模拟登陆

接着扒扒验证码的url。

验证码

抓取正常登录下的http请求。

模拟登陆审查元素

可以看到浏览器以post方式向服务器提交了用户名(学号),密码和验证码。(密码都以明文方式发送而且走的是http,安全意识感人)

这里确保提交表单时和获取验证码使用了相同的cookie,否则输入验证码会一直报错。

捣鼓

首先创建一个cookie容器来存放登录验证码url时的cookie数据,通过用户的输入生成post表单数据,通过抓取的http请求构造heander,再以刚刚获取的cookiejar生成handler,最终生成一个opener对象,传递给open方法,即成功提交了post请求。

import urllib2
import cookielib
import sys
import os

urne = raw_input('请输入学号: ')
pswd = raw_input('请输入密码: ')

# 防止中文报错
reload(sys)
sys.setdefaultencoding("utf-8")

# 验证码地址和post地址
CaptchaUrl = "http://www.xxx.edu/ssfw/jwcaptcha.do"
PostUrl =="http://www.xxx.edu/ssfw/j_spring_ids_security_check"

# 将cookies绑定到一个opener cookie由cookielib自动管理
cookie = cookielib.CookieJar()
handler = urllib2.HTTPCookieProcessor(cookie)
opener = urllib2.build_opener(handler)

# 用openr访问验证码地址,获取cookie
picture = opener.open(CaptchaUrl).read()

# 保存验证码到本地
local = open('image.jpg', 'wb')
local.write(picture)
local.close()

# 打开保存的验证码图片 输入
os.startfile("image.jpg")
SecretCode = raw_input('请输入验证码: ')

# 根据抓包信息 构造表单
postData = {
'j_username':urne,
'j_password': pswd,
'validateCode': SecretCode,}

# 根据抓包信息 构造headers
headers = {
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding":"gzip, deflate",
"Accept-Language":"zh-CN,zh;q=0.8",
"Cache-Control":"max-age=0",
"Connection":"keep-alive",
"Content-Length":"59",
"Content-Type":"application/x-www-form-urlencoded",
"Upgrade-Insecure-Requests":"1",
"User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36",}

# 生成post数据 构造?key1=value1&key2=value2的形式
data = urllib.urlencode(postData)

#发送请求
request = urllib2.Request(PostUrl, data, headers)
response = opener.open(request)

--

Cookie自动输入

有时还是嫌手动输入太麻烦,而且选课系统不允许一个用户同时在多个地方登录,用上一种方法模拟登陆后原有的浏览器的cookie就失效了.

直接提取已登录成功的cookie岂不是更方便,而且可以脚本和浏览器同时登录而互不影响,cookie登录也是反反爬虫的惯用做法。

为了更方便地导出chrome中的cookie可以使用EditThisCookie(好多次看成eatthiscookie)

editthiscookies

在浏览器中点击这款插件的图标,点击向右的按钮复制到剪贴板,这里我将其保存为cookie.txt,并且放置在和脚本相同的目录下。

cookies.txt

现在可以省掉输入用户名,密码和验证码的步骤了,一个cookie通通搞定。

cookie_jar = cookielib.MozillaCookieJar()
cookies = open('cookies.txt').read()

for cookie in json.loads(cookies):
    cookie_jar.set_cookie(cookielib.Cookie(version=0, name=cookie['name'], value=cookie['value'], port=None, port_specified=False, domain=cookie['domain'], domain_specified=False, domain_initial_dot=False, path=cookie['path'], path_specified=True, secure=cookie['secure'], expires=None, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False))

handler = urllib2.HTTPCookieProcessor(cookie_jar)
opener = urllib2.build_opener(handler)

request = urllib2.Request(PostUrl)
response = opener.open(request)


检测脚本是否登录成功登录成功

但是怎么知道脚本登录是否成功呢,一开始我的想法是:正常登录成功过后的response中的html内容中会含有姓名,班级等等一些信息,但是如果单纯正则表达式匹配,寻找DOM节点将变得相(gen)当(ben)复(bu)杂(hui),当然Python的第三方库也可以解析html,例如BeautifulSoup,功能很强大,但解析的速度很成问题,那有没有其他的办法呢。

于是我继续点击其他的按钮,同时观察http请求。

一会儿就发现规律了,每次点击触发http请求的元素时,客户端总是会发送一个get请求来获取登录状态,服务端返回一个json,在线为True,离线为False(简直像调用API一样方便)

选课请求分析

进入选课界面,写此文时正好赶上专业外通识课的选课时间,这个课是抢不完的,随便选一节课做试验。

首先看看点击选课按钮后发生了些什么请求

点击选课发生的相应

可以看到一共有三个http请求

获取当前时间

可以看到第一项为获取服务器当前时间,返回一个json

抢课请求1

第二项加了一个类似ID的参数,分析后可以知道是课程ID,获取这个ID应该可以从选课界面入手。

果不其然,对按钮审查元素过后就可以看到课程ID

课程id

由于是测试的时候是公选课,所以还带有一个xkzy(选课志愿),不加默认为第一志愿,同意response返回一个json,第一个参数判断选课是否成功,如果成功,则第二个参数为当前时间,如果选课不成功,则返回失败原因。

成功返回

安可信A7模块拨号脚本

更新记录

20170706 初次成文

为什么有这篇文章

之前树莓派和fl2440都成功使用3G模块接入互联网,但使用A7模块的配置总是卡在第一步的AT,后来检查发现3G模块的拨号AT指令前都加上了\r,其实加不加对3G模块A7的排错能力太弱,\rAT并不能识别为AT,因此所有AT命令前面的\r都要去掉,这里简要记录一下拨号脚本。

继续阅读