用python模拟网页数据提交

背景

做实验的时候,需要将独立测试集的数据与别人server跑出来的结果进行比较,比如下面这个:http://bioinfo.ggc.org/bindn/ 。但是这个server一次性只能提交一个fasta文件,也就是说,我有很多数据的话,就要分多次提交。如果是人工的去操作,会比较耗时,而且工作量特别大,因此这里就需要模拟网页的数据提交。这就是本文的主要内容,

思路

下面先来理清下思路。我的目的是通过自己构造post数据来实现数据提交。

当模拟在网页上提交数据时,首先要弄清楚整个数据处理流程,比如发送了什么样的数据,给谁发的等。那么如果我要在网页上提交数据的话,肯定是要传递参数的,所以我们要知道如何查找这些参数,这是最重要的一点。其次,模拟数据提交,必须要知道提交前的网页和提交后的网页,这样才能将提交后显示结果网页保存下来。最后就是数据处理了,使用正则表达式将需要的数据抽取出来。

实践

参数分析

关于参数,可以从数据包中分析出来,我是使用google自带的抓包工具分析的,使用ctrl+shift+I快捷键,点击进入Network列,如下图:

可以看到,当前什么都没有,下面我将参数填写完整

当我将数据设置好之后,点击Submit Query按钮后,结果如下图所示:

多了一个bindn.pl文件,我们来看看这个文件的内容,看看headers部分:

和图二进行比较,你会看到是相互对应。也就是说,这就是我们需要提交的参数:

1
2
3
4
5
6
postData = {'seq' : oneseq,  #oneseq是一个字符串,后面作为一个参数传递进来
'qtype' : 'rna',
'vtype' : 'sp',
'val' : '80',
'submit' : 'Submit Query'
}

而点击发送后的请求URL和HTML头内容,如下图:

所以现在我们可以得到以下这些数据(postData在上面已经分析出来了):

1
2
3
4
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请求的发送和相应的接收。最后需要编写一个函数,将自己需要的内容抽取出来。完整代码和讲解如下如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# -*- 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\nMKFYTISSKYIEYLKEFDDKVPNSEDPTYQNPKAFIGIVLEIQGHKYLAPLTSPK\
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)