内容简要

   1分析网站

   2简单爬取

   3进阶自定义爬取

   4保存进数据库

学校基础设施太差,宿舍电量过低提醒虽然贴在楼下,但是作为低头一族,经常忘记看提醒导致宿舍酣战时突然黑屏,为了避免这种尴尬的场景以及强化PY学习,我决定制作一个简单的爬虫。

首先我通过学校的微信公众号找到了一个十分隐蔽的查低电量提醒网站。它的界面是这样的:

手机适应的页面当然在电脑上会有一些崩=。=,但是不要介意,我们要的是功能。下面是查询到的界面

虽然看起来low而且经常不更新,但是它至少能用。于是我决定用它来制作低电量提醒查询脚本。审查元素,我们可以发现

<form action="/houqin/store/findone.action" method="post" enctype="multipart/form-data" id="form22">
<input type="hidden" name="kindId" value="9">
<div>
<table style="width:100%;border-collapse:collapse;height:70px;border-collapse:collapse;">
<tbody><tr>
<td style="width:30%;">
<table style="width:100%;border-collapse:collapse;"> <tbody><tr style="width:100%;height:50px;">
<td style="padding-left:3px;">
<font face="宋体" color="#4682B4" size="3"><strong>&nbsp;&nbsp;宿舍区域</strong></font>
</td>
</tr>
<tr style="height:20px;"></tr> <tr style="width:100%;height:50px;">
<td style="padding-left:3px;">
<font face="宋体" color="#4682B4" size="3"><strong>&nbsp;&nbsp;楼号</strong></font>
</td>
</tr>
<tr style="height:20px;"></tr> <tr style="width:100%;height:50px;">
<td style="padding-left:3px;">
<font face="宋体" color="#4682B4" size="3"><strong>&nbsp;&nbsp;宿舍号</strong></font>
</td>
</tr>
<tr style="height:20px;"></tr> <tr style="width:100%;height:50px;">
<td style="padding-left:3px;">
<font face="宋体" color="#4682B4" size="3"><strong>&nbsp;&nbsp;截止时间</strong></font>
</td>
</tr>
<tr style="height:20px;"></tr> <tr style="width:100%;height:50px;">
<td style="padding-left:3px;">
<font face="宋体" color="#4682B4" size="3"><strong>&nbsp;&nbsp;剩余电量</strong></font>
</td>
</tr>
<tr style="height:20px;"></tr> <tr style="width:100%;height:50px;">
<td style="padding-left:3px;">
<font face="宋体" color="#4682B4" size="3"><strong>&nbsp;&nbsp;</strong></font>
</td>
</tr>
<tr style="height:20px;"></tr> </tbody></table>
</td>
<td style="width:70%;">
<table style="width:100%;border-collapse:collapse;" id="taet"> <tbody><tr style="width:100%;height:50px;">
<td>
<input type="text" name="search.text0" id="text0" value="" style="border: 2 solid #FAF0E6; width:80%;height:40px;font-size: 17px;font-weight: 800;color:#4682B4"> </td>
</tr>
<tr style="height:20px;"></tr>
<tr style="width:100%;height:50px;">
<td>
<input type="text" name="search.text1" id="text1" value="" style="border: 2 solid #FAF0E6; width:80%;height:40px;font-size: 17px;font-weight: 800;color:#4682B4">
</td>
</tr>
<tr style="height:20px;"></tr>
<tr style="width:100%;height:50px;">
<td>
<input type="text" name="search.text2" id="text2" value="" style="border: 2 solid #FAF0E6; width:80%;height:40px;font-size: 17px;font-weight: 800;color:#4682B4">
</td>
</tr>
<tr style="height:20px;"></tr>
<tr style="width:100%;height:50px;">
<td>
<input type="text" name="search.text3" id="text3" value="" style="border: 2 solid #FAF0E6; width:80%;height:40px;font-size: 17px;font-weight: 800;color:#4682B4">
</td>
</tr>
<tr style="height:20px;"></tr>
<tr style="width:100%;height:50px;">
<td>
<input type="text" name="search.text4" id="text4" value="" style="border: 2 solid #FAF0E6; width:80%;height:40px;font-size: 17px;font-weight: 800;color:#4682B4">
</td>
</tr>
<tr style="height:20px;"></tr>
<tr style="width:100%;height:50px;">
<td>
<input type="text" name="search.text5" id="text5" value="" style="border: 2 solid #FAF0E6; width:80%;height:40px;font-size: 17px;font-weight: 800;color:#4682B4">
</td>
</tr>
<tr style="height:20px;"></tr>
</tbody></table>
</td>
</tr>
<tr style="height:40px;"></tr>
<tr style="width:100%;height:70px;background:#FFFFFF;">
<td colspan="2" align="center">
<input type="button" onclick="subhdhp();" value="提交" style="width:80%;height:40px;background:#4682B4;color:#FFFFFF; font-size:17px;font-weight:900; border: 0px;">
</td>
</tr>
</tbody></table> </div>
<br>
<br><br> </form>

完整表单信息

简化重要的部分,可以看出,这个表单有用的信息有如下代码:

<form action="/houqin/store/findone.action" method="post" enctype="multipart/form-data" id="form22">
<input type="hidden" name="kindId" value="9">
<div>
<table >
<tbody>
<tr>
<td >
<table id="taet">
<tbody><tr >
<td>
<input type="text" name="search.text0" id="text0" value="">
</td>
</tr>
<tr>
<td>
<input type="text" name="search.text1" id="text1" value="">
</td>
</tr> <tr >
<td>
<input type="text" name="search.text2" id="text2" value="">
</td>
</tr> <tr>
<td>
<input type="text" name="search.text3" id="text3" value="">
</td>
</tr> <tr>
<td>
<input type="text" name="search.text4" id="text4" value="">
</td>
</tr>
<tr></tr>
<tr>
<td>
<input type="text" name="search.text5" id="text5" value="">
</td>
</tr> </tbody></table>
</td>
</tr> <tr>
<td colspan="2" align="center">
<input type="button" onclick="subhdhp();" value="提交">
</td>
</tr>
</tbody></table>
</div></form>

简化版HTML

提取完以后感觉难度就降低了不少。但是只用填前3个空就能查询到。我觉得后几个空可能会设定一些防止爬取的障碍,我使用审查元素中自带的查询network功能看了一下。在一个post方法中我找到了如下数据:

------WebKitFormBoundaryOJwEBCeqt5bb9jEZ
Content-Disposition: form-data; name="kindId" 9
------WebKitFormBoundaryOJwEBCeqt5bb9jEZ
Content-Disposition: form-data; name="search.text0" 北区
------WebKitFormBoundaryOJwEBCeqt5bb9jEZ
Content-Disposition: form-data; name="search.text1" 3
------WebKitFormBoundaryOJwEBCeqt5bb9jEZ
Content-Disposition: form-data; name="search.text2" 537
------WebKitFormBoundaryOJwEBCeqt5bb9jEZ
Content-Disposition: form-data; name="search.text3" ------WebKitFormBoundaryOJwEBCeqt5bb9jEZ
Content-Disposition: form-data; name="search.text4" ------WebKitFormBoundaryOJwEBCeqt5bb9jEZ
Content-Disposition: form-data; name="search.text5" ------WebKitFormBoundaryOJwEBCeqt5bb9jEZ--

Post 数据

这跟我之前见到的post格式不同,上网查了一下,这是一种叫做multipart/form-data格式的post,它能把post信息以二进制形式发送过去,所以还能用来传送文件。做个小脚本还能学到这样的新知识。阅历+1.

根据它的基本信息。我写了如下的代码来post并抓取得到的网页全内容

# -*- coding: utf-8 -*-

import urllib2
import urllib url='http://hqsz.ouc.edu.cn/houqin/store/findone.action' boundary='---------------------------12174501422663' #分隔符
data = []
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="kindId" ')
data.append('')
data.append('9 ' )
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text0" ')
data.append('')
data.append('北区 ')
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text1" ')
data.append('')
data.append('3 ')
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text2" ')
data.append('')
data.append('537 ')
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text3" ')
data.append('')
data.append('')
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text4" ')
data.append('')
data.append('')
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text5" ')
data.append('')
data.append('')
data.append('--'+boundary+'--')
data.append('')
httpbody='\r\n'.join(data)
print type(httpbody)
content_type='multipart/form-data; boundary=%s' %boundary
print content_type
req = urllib2.Request(url,httpbody)
req.add_header("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
req.add_header("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:46.0) Gecko/20100101 Firefox/46.0")
req.add_header("Referer","http://hqsz.ouc.edu.cn/houqin/store/findmessage.action?kindId=9")
req.add_header("Content-Type", content_type )
req.add_header("Accept-Language","zh-CN,en-US;q=0.7,en;q=0.3")
req.add_header("Accept-Encoding","gzip, deflate")
req.add_header("Connection","keep_alive")
response = urllib2.urlopen(req)
html = response.read()
print html

抓取网页

这段代码分为2个部分,前半部分是表单生成。后半部分是模拟浏览器头,虽然这个网站并不会检测,但是为了学习还是要写这一部分强化记忆。对于表单生成这部分,我得到了如下的公式:对于multipart/form-data这样的信息一般可以用如下格式:

这其中的data.append('')是必加的,图省事省略掉就错了。

这样的代码只能针对一个人的,不能由用户输入,这样感觉很不好,于是我选择加上用户输入。先把以上函数封装成一个函数Search_e(eara,house,room);

之后在py中调用这个函数就行了,代码如下:

# -*- coding: utf-8 -*-
# encoding: utf-8
import urllib2,re
import urllib def Search_e(eara,house,room):
#post的目标地址
url='http://hqsz.ouc.edu.cn/houqin/store/findone.action'
#设置post的数据
boundary='---------------------------12174501422663' #分隔符
data = []
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="kindId"')
data.append('')
data.append('' )
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text0"')
data.append('')
data.append(eara)
#查询房间所在区域
#data.append('北区')
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text1"')
data.append('')
#查询房间所在的楼号
data.append(house)
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text2"')
data.append('')
#查询房间的房间号
data.append(room)
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text3"')
data.append('')
data.append('')
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text4"')
data.append('')
data.append('')
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text5"')
data.append('')
data.append('')
data.append('--'+boundary+'--')
data.append('')
httpbody='\r\n'.join(data)
#以上部分就是查询信息的表单
content_type='multipart/form-data; boundary=%s' %boundary
#print data #检验表单数据
req = urllib2.Request(url,httpbody)
req.add_header("Content-Type", content_type )
req.add_header("Accept-Language","zh-CN,en-US;q=0.7,en;q=0.3")
req.add_header("Accept-Encoding","gzip, deflate")
#req.add_header("Connection","keep_alive")
response = urllib2.urlopen(req)
html = response.read()
unicodePage=html.decode("utf-8")
pattern=ur"<strong>([\s\S]*?)<\/strong>"
result=re.findall(pattern,unicodePage,re.S)
try:
if(result[11]):
print u"剩余电量",result[11],u"请及时交电费"
except:
print u"电量充足" eara=raw_input("请输入区域(北区,东区,南区):")
eara=eara.decode('gbk').encode('utf-8') #将输入的Gbk字符转化为utf-8字符
house=raw_input("请输入楼号(例如1号楼:1):")
room=raw_input("请输入房间号(例如110房间:110):")
Search_e(eara,house,room)

用户自定义友好

光查询还不能满足我,我还想知道最近的用电情况,我决定把他们保存在数据库中进行分析。

于是我更换了如下代码,

# -*- coding: utf-8 -*-
# encoding:utf-8
import urllib2,re
import urllib
import MySQLdb as db def Search_e(eara,house,room):
#post的目标地址
url='http://hqsz.ouc.edu.cn/houqin/store/findone.action'
#设置post的数据
boundary='---------------------------12174501422663' #分隔符
data = []
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="kindId"')
data.append('')
data.append('' )
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text0"')
data.append('')
#data.append(eara)
#查询房间所在区域
data.append('北区')
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text1"')
data.append('')
#查询房间所在的楼号
data.append(house)
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text2"')
data.append('')
#查询房间的房间号
data.append(room)
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text3"')
data.append('')
data.append('')
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text4"')
data.append('')
data.append('')
data.append('--'+boundary)
data.append('Content-Disposition: form-data; name="search.text5"')
data.append('')
data.append('')
data.append('--'+boundary+'--')
data.append('')
httpbody='\r\n'.join(data)
#以上部分就是查询信息的表单
content_type='multipart/form-data; boundary=%s' %boundary
#print data #检验表单数据
req = urllib2.Request(url,httpbody)
req.add_header("Content-Type", content_type )
req.add_header("Accept-Language","zh-CN,en-US;q=0.7,en;q=0.3")
req.add_header("Accept-Encoding","gzip, deflate")
#req.add_header("Connection","keep_alive")
response = urllib2.urlopen(req)
html = response.read()
unicodePage=html.decode("utf-8")
pattern=ur"<strong>([\s\S]*?)<\/strong>"
result=re.findall(pattern,unicodePage,re.S)
try:
return result[11]
except:
return '20.0' connection = db.connect(host='localhost',user='root',passwd='root',db='oucect',port=3306,init_command='set names utf8')
cursor = connection.cursor()
cursor.execute("select * from rooms");
result = cursor.fetchall()
cursor.close()
connection.close()
print result
for item in result:
aera=item[3]
house = item[1]
room = item[2]
num=Search_e(aera,house,room)
connection = db.connect(host='localhost',user='root',passwd='root',db='oucect',port=3306,init_command='set names utf8')
cursor = connection.cursor()
cursor.execute("update rooms set ect = "+num+" where id="+str(item[0]));
connection.commit();
cursor.close();
connection.close();

保存数据库版本

现在这样就可以保存进数据库了,但是这个网站几乎是7-5天更新一次,我现在还不会计划任务爬取网页进行分析,我要学习的还有很多,现在一个用C#写出来的自动发邮件的小程序已经完成。我相信我就能够一点一点变成大神的。

用Python实现一个爬取XX大学电费通知的小脚本的更多相关文章

  1. python爬取中国大学排名

    教程来自:[Python网络爬虫与信息提取].MOOC. 北京理工大学 目标:爬取最好大学网前50名大学 代码如下: import requests from bs4 import Beautiful ...

  2. Python爬虫之爬取站内所有图片

    title date tags layut Python爬虫之爬取站内所有图片 2018-10-07 Python post 目标是 http://www.5442.com/meinv/ 如需在非li ...

  3. python爬虫实战---爬取大众点评评论

    python爬虫实战—爬取大众点评评论(加密字体) 1.首先打开一个店铺找到评论 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经 ...

  4. [python] 常用正则表达式爬取网页信息及分析HTML标签总结【转】

    [python] 常用正则表达式爬取网页信息及分析HTML标签总结 转http://blog.csdn.net/Eastmount/article/details/51082253 标签: pytho ...

  5. Python爬虫之爬取慕课网课程评分

    BS是什么? BeautifulSoup是一个基于标签的文本解析工具.可以根据标签提取想要的内容,很适合处理html和xml这类语言文本.如果你希望了解更多关于BS的介绍和用法,请看Beautiful ...

  6. [Python爬虫] Selenium爬取新浪微博客户端用户信息、热点话题及评论 (上)

    转载自:http://blog.csdn.net/eastmount/article/details/51231852 一. 文章介绍 源码下载地址:http://download.csdn.net/ ...

  7. 如何利用Python网络爬虫爬取微信朋友圈动态--附代码(下)

    前天给大家分享了如何利用Python网络爬虫爬取微信朋友圈数据的上篇(理论篇),今天给大家分享一下代码实现(实战篇),接着上篇往下继续深入. 一.代码实现 1.修改Scrapy项目中的items.py ...

  8. from appium import webdriver 使用python爬虫,批量爬取抖音app视频(requests+Fiddler+appium)

    使用python爬虫,批量爬取抖音app视频(requests+Fiddler+appium) - 北平吴彦祖 - 博客园 https://www.cnblogs.com/stevenshushu/p ...

  9. 利用Python网络爬虫爬取学校官网十条标题

    利用Python网络爬虫爬取学校官网十条标题 案例代码: # __author : "J" # date : 2018-03-06 # 导入需要用到的库文件 import urll ...

随机推荐

  1. FreeMark学习(三)

    沉淀的心   freemarker学习笔记--设计指导   <# ... > 中存放所有freemaker的内容,之外的内容全部原样输出.<@ ... /> 是函数调用两个定界 ...

  2. 会话状态已创建一个会话 ID,但由于响应已被应用程序刷新而无法保存它

    解决方法是新建 全局应用程序类 Global.asax 在 Session_Start 函数中 添加 string sessionId = Session.SessionID; protected v ...

  3. PHP禁止同一IP频繁访问以防止网站被防攻击或采集的代码

    PHP禁止同一IP频繁访问以防止网站被防攻击或采集的代码 <?php /* *通过禁止IP频繁访问防止网站被防攻击代码*design by www.scutephp.com*/header('C ...

  4. Python语法二

    1.raw_input 输入 2.如果想查看某个关键字的用法,可以在命令行输入pydoc raw_input. 如果是windows,那么试一下 python -m pydoc raw_input 3 ...

  5. sip常用消息实体参考(系网上摘抄,感谢分享)

    1.MESSAGE消息       1)头字段填写说明       Call-id:                 必选       CSeq:                   必选       ...

  6. CListCtlr 控件的常见用法

    今天第一次用CListCtrl控件,遇到不少问题,查了许多资料,现将用到的一些东西总结如下: 以下未经说明,listctrl默认view 风格为report 相关类及处理函数 MFC:CListCtr ...

  7. MVP模式和MVVM模式

    MVP模式 模型-视图-表示器,也就是MVP模式.是mvc模式的一种衍生模式,专注于改进表示逻辑. 与MVC不同,来自view的调用将委托给presenter(表示器),表示器通过接口与view对话. ...

  8. [译]Node.js - Event Loop

    介绍 在读这篇博客之前,我强列建议先阅读我的前两篇文章: Getting Started With Node.js Node.js - Modules 在这篇文章中,我们将学习 Node.js 中的事 ...

  9. angularJs基础

    AngularJs是为了克服Html在构建应用上的不足而设计的.Html是一门很好的为静态文件展示设计的声明式语言,但是要构建web应用的话就显得乏力了.所以我做了一些工作来让浏览器做我瞎向要的事. ...

  10. 解决SOAPCLIENT访问WebSerivce外网发布端口

    猫用vs2010写了一个webservice,并写了一个盘点程序客户端,PDA盘点机用C#开发,笔记本用VFP开发,发布在本地局域网IIS服务器,用了两年一直很稳定.后面仓库搬迁,需要外网进行访问,在 ...