用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/