女神找我倾诉,实验室实验选不上,刚出来就被秒了,让我帮她选实验,我想我这万年单身的手速估计还是抢不过我这些师兄们,干脆写一个脚本吧,这样以后女神就找我选实验了,废话少说,切入主题,看这篇教程首先得保证你有Python基础,我尽量会写的通俗易懂,记录下思考的整个过程。
先来看一个简单的爬虫脚本
先不要想这个复杂的功能,我们想想能不能用Python浏览一个网页,就从最简单的抓取百度主页开始。PS:要用Python3哦~
import urllib.request
url = "http://www.baidu.com"
data = urllib.request.urlopen(url)
print(data.read().decode('UTF-8'))
上述代码的输出就是百度主页的html代码,对于爬虫的类库,不懂直接可以套用,这里我来解释一下编码的问题,看你需要爬的网页源码,Google浏览器右键检查,开头会有<meta charset="***">
其中*就是网页的编码方式,因为Python内部使用unicode编码,所以要转为网页编码方式。
深入一点-模拟登陆
现在正式切入我们要实现的脚本,模拟登陆网站,然后模拟提交数据。先大概解释一下流程,我们登陆网站时,输入账号密码,网站会给浏览器发送一个cookie的东西,浏览器下次访问网页时,会将这个cookie发送给服务器,服务器就会知道是谁访问它了,所以我们模拟的时候,最关键的就是把这个cookie存起来。先看源码:
import urllib.request
import http.cookiejar
import urllib.parse
postData = {
'username': '***',
'pass': '***',
'password': '***'
}
url = '***'
cookie = http.cookiejar.CookieJar()
openner = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie))
headers = {
'User-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
}
request = urllib.request.Request(url, urllib.parse.urlencode(postData).encode(), headers)
r = openner.open(request)
print(r.read().decode('UTF-8'))
为了避嫌,这里我讲网页链接去掉,注意到账号和密码是保存在postData的字典中,还需要header参数,其他都是固定写法,没什么好解释的,下面我主要说明这postData和header参数是怎么构造的。
用Google浏览器打开你要登陆的网页,右键检查,点network选项
输入账号和密码,点登陆,这时候可以看到右侧抓取了内容,我们点第一个,点击就OK
现在可以看到我们构建的postData和header是从哪里来的了吧,postData的内容要保证一样,header可以不用全部构建,一般构建User-Agent和Referer就够了,如果你还爬不进去,不妨再加点别的参数试试。
更进一步-模拟post提交参数
经过上面的步骤,相信我们都可以登录进入网页了,下面我们要做的就是如何自动的填写参数,然后提交到网站上去。先看这部分的代码实现:
exUrl = "http://atc.hust.edu.cn:8080/lioms4hz/order/load?id=5"
exPostData = {
'proSource': '111',
'proNum': '111',
'proName': '111',
'sampleName': '111',
'sampleCount': '111',
'sampleDetail': '111',
'sampleImg': '',
'dpId': '50',
'testDate': '2017-04-17',
'startTime': '14:00:00',
'endTime': '16:00:00',
'startTime1': '',
'endTime1': '',
'startTime2': '',
'endTime2': '',
'remarks': '111',
'uiid': '1784',
'diid': '5',
'parentid': '154',
'duser': '474',
'query': '1'
}
exheaders = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
'Referer': '***',
'Origin': '***'
}
exRequest = urllib.request.Request(exUrl, urllib.parse.urlencode(exPostData).encode(), exheaders)
exr = openner.open(exRequest)
response = exr.read().decode('UTF-8')
对于post的数据和header的参数的选择,经过上述的步骤相信都可以解决了,这里要注意的时,我们再次访问网站的时候需要要来的cookie,exr = openner.open(exRequest)
这一行代码可以保证将原来保存的cookie再次提交到网站。
总结
OK!写到这里,相信大部分人可以完成一个简单的爬虫程序了,当然爬虫的功能不仅仅局限于这里,当获取一个网页的html源码时,我们可以利用正则表达式,获取对我们有用的信息,从而可以完成更加复杂的功能。
将实现的整个代码上传到服务器上,再服务器安装Python3,可以利用crontab定时任务定时执行我们的脚本,比如说女神的实验是晚上9点开始选,那我们可以设定9点开始执行,命令如下:
[root@localhost ~]# crontab -e
0 21 * * * /bin/python3 /home/test.py > /home/test.log
crontab具体的配置过程可以看我的另一篇博客
http://blog.csdn.net/hxl_1993/article/details/52024943
下面帖出我实现的整个代码,为了保证万无一失,脚本从8点59开始执行,成功选上实验或者执行2分钟后退出。
import urllib.request
import http.cookiejar
import urllib.parse
import re
import datetime
postData = {
'username': '***',
'pass': '***',
'password': '***'
}
url = '***'
cookie = http.cookiejar.CookieJar()
openner = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie))
headers = {
'User-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
}
request = urllib.request.Request(url, urllib.parse.urlencode(postData).encode(), headers)
r = openner.open(request)
# print(r.read().decode('UTF-8'))
exUrl = "***"
exPostData = {
'proSource': '111',
'proNum': '111',
'proName': '111',
'sampleName': '111',
'sampleCount': '111',
'sampleDetail': '111',
'sampleImg': '',
'dpId': '50',
'testDate': '2017-04-17',
'startTime': '14:00:00',
'endTime': '16:00:00',
'startTime1': '',
'endTime1': '',
'startTime2': '',
'endTime2': '',
'remarks': '111',
'uiid': '1784',
'diid': '5',
'parentid': '154',
'duser': '474',
'query': '1'
}
exheaders = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
'Referer': '***',
'Origin': '***'
}
flag = True
noPattern = re.compile("class=\"alert fade in alert-danger\".*?抱歉", re.S)
start = datetime.datetime.now()
end = datetime.datetime.now()
# 如果失败发起多次请求
while flag and (end-start).seconds < 120:
end = datetime.datetime.now()
try:
exRequest = urllib.request.Request(exUrl, urllib.parse.urlencode(exPostData).encode(), exheaders)
exr = openner.open(exRequest)
response = exr.read().decode('UTF-8')
flag = False
noStr = noPattern.findall(response)
if noStr:
print('no')
else:
print('yes')
except urllib.error.URLError as e:
flag = True
print(e.code, ':', e.reason)
open('index.html', 'w', encoding='UTF-8').write(response)