用python模擬網頁數據提交
背景
做實驗的時候,需要將獨立測試集的數據與別人server跑出來的結果進行比較,比如下面這個: http://bioinfo.ggc.org/bindn/ 。但是這個server一次性只能提交一個fasta文件,也就是說,我有很多數據的話,就要分多次提交。如果是人工的去操作,會比較耗時,而且工作量特別大,因此這里就需要模擬網頁的數據提交。這就是本文的主要內容,
思路
下面先來理清下思路。我的目的是通過自己構造post數據來實現數據提交。
當模擬在網頁上提交數據時,首先要弄清楚整個數據處理流程,比如發送了什么樣的數據,給誰發的等。那么如果我要在網頁上提交數據的話,肯定是要傳遞參數的,所以我們要知道如何查找這些參數,這是最重要的一點。其次,模擬數據提交,必須要知道提交前的網頁和提交后的網頁,這樣才能將提交后顯示結果網頁保存下來。最后就是數據處理了,使用正則表達式將需要的數據抽取出來。
實踐
參數分析
關于參數,可以從數據包中分析出來,我是使用google自帶的抓包工具分析的,使用ctrl+shift+I快捷鍵,點擊進入Network列,如下圖:
可以看到,當前什么都沒有,下面我將參數填寫完整
當我將數據設置好之后,點擊Submit Query按鈕后,結果如下圖所示:
多了一個bindn.pl文件,我們來看看這個文件的內容,看看headers部分:
和圖二進行比較,你會看到是相互對應。也就是說,這就是我們需要提交的參數:
postData = {'seq' : oneseq, #oneseq是一個字符串,后面作為一個參數傳遞進來 'qtype' : 'rna', 'vtype' : 'sp', 'val' : '80', 'submit' : 'Submit Query' }
而點擊發送后的請求URL和HTML頭內容,如下圖:
所以現在我們可以得到以下這些數據(postData在上面已經分析出來了):
hosturl = 'http://bioinfo.ggc.org/bindn/' posturl = 'http://bioinfo.ggc.org/cgi-bin/bindn/bindn.pl' #可以從數據包中分析出,處理post請求的url headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36', 'Referer' : 'http://bioinfo.ggc.org/bindn/'}
Python模擬
分析結束后,我們要構造自己的HTTP數據包,并發送給指定url。我們通過urllib2等幾個模塊提供的API來實現request請求的發送和相應的接收。最后需要編寫一個函數,將自己需要的內容抽取出來。完整代碼和講解如下如下:
# -*- coding: utf-8 -*- """ Created on Fri Jan 01 09:34:50 2016 @author: liudiwei """ import os import urllib import urllib2 import cookielib import re #首先定義一個模擬數據提交的函數,傳入剛剛分析出來的四個參數即可 def scratchData(hosturl, posturl, postData, headers): #設置一個cookie處理器,它負責從服務器下載cookie到本地,并且在發送請求時帶上本地的cookie cj = cookielib.LWPCookieJar() cookie_support = urllib2.HTTPCookieProcessor(cj) opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler) urllib2.install_opener(opener) #打開登錄主頁面(他的目的是從頁面下載cookie,這樣我們在再送post數據時就有cookie了,否則發送不成功) urllib2.urlopen(hosturl) #需要給Post數據編碼 postDataEncode = urllib.urlencode(postData) #通過urllib2提供的request方法來向指定Url發送我們構造的數據,并完成數據發送過程 request = urllib2.Request(posturl, postDataEncode, headers) print request response = urllib2.urlopen(request) resultText = response.read() return resultText #將一次提交寫到一個函數里面,每次只需傳入一個序列即可,因為其它的參數不變 def BindN(oneseq, outdir): #當前頁面,即提交數據頁面 hosturl = 'http://bioinfo.ggc.org/bindn/' #post數據接收和處理的頁面(我們要向這個頁面發送我們構造的Post數據) posturl = 'http://bioinfo.ggc.org/cgi-bin/bindn/bindn.pl' #可以從數據包中分析出,處理post請求的url #構造header,一般header至少要包含一下兩項。這兩項是從抓到的包里分析得出的。 headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36', 'Referer' : 'http://bioinfo.ggc.org/bindn/'} #構造Post數據,他也是從抓大的包里分析得出的。 postData = {'seq' : oneseq, 'qtype' : 'rna', 'vtype' : 'sp', 'val' : '80', 'submit' : 'Submit Query' } result = scratchData(hosturl, posturl, postData, headers) print "+++++", oneseq chainname = oneseq[1:5] + oneseq[6:7] outfilename = str(chainname) + '.html' fw_result = open(outdir + '/' + outfilename, 'w') fw_result.write(result) fw_result.close() return result, str(chainname) #使用正則表達式提取數據 def extractBindN(htmlfmt, outfile): fw_result = open(outfile, 'w') inputdata = htmlfmt.split('\n') for i in range(len(inputdata)): onedata = inputdata[i].strip() if not onedata: continue if '<' in onedata or '*' in onedata: continue regText = onedata.split('\t')[0].strip() if re.match(r'^\d+$', regText) and True or False: fw_result.write(onedata + '\n') fw_result.close() #main方法 if __name__=="__main__": oneseq = ">2XD0_A\nMKFYTISSKYIEYLKEFDDKV*NSEDPTYQNPKAFIGIVLEIQGHKYLAPLTSPK\ KWHNNVKESSLSCFKLHENGVPENQLGLINLKFMIPIIEAEVSLLDLGNMPNTPYKRMLYKQLQFIRANSDKIA\ SKSDTLRNLVLQGKMQGTCNFSLLEEKYRDFGK" outdir = "/home/liudiwei/result" #輸出路徑 if not os.path.exists(outdir): os.mkdir(outdir) print outdir result, chainname = BindN(oneseq, outdir) outfile = outdir + "/" + chainname + ".data" #最終輸出的文件名 extractBindN(result, outfile)
來自: http://www.csuldw.com/2016/01/01/2016-01-01-extracte-data-from-web-server-in-python/