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協議,愛護服務器。


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