內容簡要
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> 宿舍區域</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> 樓號</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> 宿舍號</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> 截止時間</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> 剩余電量</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> </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>
提取完以后感覺難度就降低了不少。但是只用填前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格式不同,上網查了一下,這是一種叫做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('9' ) 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('9' ) 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#寫出來的自動發郵件的小程序已經完成。我相信我就能夠一點一點變成大神的。