Python爬虫--爬取厦大电费

先放我的github链接:https://github.com/Yundi339/XMU_Electricity_Fee

电费爬取参考链接:https://blog.csdn.net/qq_39942341/article/details/84405438 ,这是另一位大佬写的博客,由于厦大电费的网站经历了几次更新,现在比以前好爬一点。

厦大电费网址,这个网站很多信息的描述花里胡哨的,使用前最好先查看一下所要填的信息在网站里面的真实描述名称。然后是这个网站服务器有时候会有问题,比如无法抓到所要的信息,无法访问,这些是服务器的问题,代码没有问题。

下面就讲讲具体怎么使用爬虫抓取厦大电费:
环境:

  • version:Python3.6
  • package:
    • requests
    • lxml

首先,对厦大电费的网站进行分析,寻找规律,然后开始设计代码思路。我的思路大致跟上面大佬的一样:
就是保持session
get访问一次获取所有隐藏的表单信息,填写其他隐藏表单信息
选取校区(因为选完页面会刷一次),post访问
填写其他信息,post得到电费

思路我先直接照搬了,与他不一样的地方是使用遍历的库不一样和一些细节优化
大佬的代码在我的电脑上跑0.65s,而他说他跑了0.7s,可能是因为他使用的是校园网爬虫(众所周知校园网很垃圾

先说明一下,我的版本大概耗时0.63s,0.02s的差距应该是遍历网页源码的耗时,因为用了三次的网页请求,所以大概耗时是在get和post上。为什么要分三次呢,因为这个网站可能是出于反爬虫的目的,有些资源设置的比较不合理(非人类
,导致获取的方式出乎意外。


我们来看看我随便选的宿舍,第一步,我们需要先获取网站的信息,然后填表单,选择校区;第二步post获取楼名,选择楼名,填写房间号;第三步post得到的信息如果在网页中将会是下面这张图的结果,我们需要抓取“账户余额…”的信息即可。
(PS:以前的电费系统要通过查询”用电量”,然后搜索当天的总余额才可以获取余额,并且以前的信息是升序而不是现在的逆序)

在这里插入图片描述


代码

修改xiaoqu,yuanqu,sushe这三个参数就能使用

# _*_ coding:utf-8 _*_
import requests
from lxml import etree

url = "http://elec.xmu.edu.cn/PdmlWebSetup/Pages/SMSMain.aspx"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10",
    "Referer": url
}


# 修改post的data参数
# @param data {'name':'value', ...}
# @param html 网页源代码
def changeData(data, html):
    data['__EVENTTARGET'] = ''
    data['__EVENTARGUMENT'] = ''
    data['__LASTFOCUS'] = ''
    names = html.xpath('//input[@type="hidden" and @value]/@name')
    values = html.xpath('//input[@type="hidden" and @value]/@value')
    for name, value in zip(names, values):
        data[name] = value


# 获取电费
# @param drxiaoqu 校区代号
# @param drlou 园区代号
# @param txtRoomid 宿舍
def query(drxiaoqu, drlou, txtRoomid):
    req = requests.session()
    data = {}
    response = req.get(url=url, headers=headers)  # 第一次请求
    html = etree.HTML(response.content.decode())
    # 获取园区信息
    drxiaoqu_value_list = html.xpath('//select[@name="drxiaoqu"]/option/@value')
    drxiaoqu_name_list = html.xpath('//select[@name="drxiaoqu"]/option/text()')
    try:
        drxiaoqu_index = drxiaoqu_name_list.index(drxiaoqu)
    except:
        return 'ERROR drxiaoqu'
    changeData(data, html)
    data['drxiaoqu'] = drxiaoqu_value_list[drxiaoqu_index]
    response = req.post(url=url, headers=headers, data=data)  # 第二次请求
    html = etree.HTML(response.content.decode())
    # 获取楼道信息
    drlou_value_list = html.xpath('//select[@name="drlou"]/option/@value')
    drlou_name_list = html.xpath('//select[@name="drlou"]/option/text()')
    try:
        drlou_index = drlou_name_list.index(drlou)
    except:
        return 'ERROR drlou'
    changeData(data, html)
    data['drlou'] = drlou_value_list[drlou_index]
    data['txtRoomid'] = txtRoomid

    response = req.post(url=url, headers=headers, data=data)  # 第三次请求
    html = etree.HTML(response.content.decode())
    result = html.xpath('//label[@class="dxeBase_Aqua" and @id="lableft"]/text()')
    return result[0] if len(result) == 1 else "ERROR txtRoomid or SERVICE BOOM!"

if __name__ == '__main__':
    xiaoqu = '本部南光区'
    yuanqu = '南光7'
    sushe = '0301'
    print(xiaoqu + ' ' + yuanqu + ' ' + sushe + ':', end='    ')
    print(query(xiaoqu, yuanqu, sushe))


上面代码的输出结果:

在这里插入图片描述

关于电费爬取使用 requests 和 lxml 两个库就可以使用了,关于还想查询其他信息,就需要根据网页源代码来一步一步分析找规律,寻找关键信息。
代码部分我只是get网页文本,然后模仿大佬的方法,用了我自己的方式抓取,有些部分我要补充一下。
1. req = requests.session()相当于是起了缓存的作用,如果不加这句,每次抓取网页信息是重新抓取。将白了,不加会导致原本0.63s的爬虫变成0.96s;
2. data是我们要发送给网站的参数,那位大佬的方法中还添加了计算时间,这个是因为以前“账户余额…”的部分服务器有问题,所以大佬大概是选择抓取当天的方式来获取余额,现在是没那个必要了(目前是,以后可能不是);
3. data[’__EVENTTARGET’] = ‘’,data[’__EVENTARGUMENT’] = ‘’,data[’__LASTFOCUS’] = ‘’,这三个你可能在debug模式下会发现没有相应的信息,这需要你用浏览器打开查源代码才能知道,相当于是隐藏参数,这个我也查了好久,最后还是看了大佬的代码才知道有这玩意儿。 不加这三个信息的话,post会返回404;
4. 代码目前我只写到个人使用的水平,如果想发展到非个人使用的,需要改许多地方,但一定要遵守robots.txt协议,爱护服务器。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章