Python 非常奇怪的Web抓取问题:Post请求未按预期运行
我试图以编程方式将一些数据提交到公司管理页面上的表单,而不是手工提交 我还写过很多其他工具,这些工具可以清理这个网站并处理数据。然而,出于某种原因,这件事给我带来了一大堆麻烦 使用浏览器浏览: 下面是我试图搜集和发布数据的页面。请注意,这些页面通常显示在js阴影框中,但是,如果禁用Javascript,它的功能会很好,因此我假设Javascript与scraper问题无关 (注意,由于这是一个公司页面,我已经填写了我已经用垃圾标题替换了所有的表单字段,因此,例如,客户号码完全是虚构的) 另外,由于这是一个用户名/密码墙后面的公司页面,我不能提供网站进行测试,所以我尝试在这篇文章中尽可能多地注入细节 主要切入点如下: 在这个页面中,我单击“添加新表单”,这将在一个新标签中打开下一个页面(因为禁用了javascript) 在这个页面上,我填写小表单,单击submit,然后进入下一个页面,显示一条成功消息 应该很简单,对吗 代码尝试1:机械化 因此,正如您所看到的,我尝试复制在浏览器中执行的步骤。我加载初始的Python 非常奇怪的Web抓取问题:Post请求未按预期运行,python,web-scraping,urllib2,mechanize,Python,Web Scraping,Urllib2,Mechanize,我试图以编程方式将一些数据提交到公司管理页面上的表单,而不是手工提交 我还写过很多其他工具,这些工具可以清理这个网站并处理数据。然而,出于某种原因,这件事给我带来了一大堆麻烦 使用浏览器浏览: 下面是我试图搜集和发布数据的页面。请注意,这些页面通常显示在js阴影框中,但是,如果禁用Javascript,它的功能会很好,因此我假设Javascript与scraper问题无关 (注意,由于这是一个公司页面,我已经填写了我已经用垃圾标题替换了所有的表单字段,因此,例如,客户号码完全是虚构的) 另外,由
/adm/forms
页面,按照第一个链接,即添加表单
,填写表单,然后单击提交
按钮。但这就是问题的症结所在。mechanize返回的响应与表单完全相同。没有错误消息,没有成功消息,当我手动检查我们的管理页面时,没有进行任何更改
检查网络活动
沮丧的是,我打开Chrome,看着网络标签,在浏览器中手动填写并提交表单
提交表格后,这是网络活动:
对我来说似乎很直截了当。css文件有post
,然后是get
,jquery库有另一个get
。还有另一个get
用于某种图像,但我不知道这是为了什么
检查POST请求的详细信息:
在谷歌搜索了一些关于抓取问题的信息后,我看到一个建议,服务器可能需要某个标题,我应该简单地复制POST请求中的所有内容,然后慢慢地删除标题,直到我知道哪一个是重要的。所以我就这么做了,复制了网络标签上的每一点信息,并坚持我的发帖请求
代码尝试2:Urllib
我在使用Mechanize
时遇到了一些麻烦,所以我切换到了urllib2
import urllib
import urllib2
import base64
url = 'www.our_company_page.com/adm/add_forms.php'
values = {
'SID':'', #Hidden field
'FormNumber':'FROM_PYTHON1030PM',
'RevisionNumber':'5',
'FormType':'H(num)',
'fsubmit':'Save Page'
}
username = 'USERNAME'
password = 'PASSWORD'
headers = {
'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Charset' : 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
'Accept-Encoding' : 'gzip,deflate,sdch',
'Accept-Language' : 'en-US,en;q=0.8',
'User-Agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
'Authorization': 'Basic %s' % base64.encodestring('%s:%s' % (username, password)),
'Cache-Control' : 'max-age=0',
'Connection' : 'keep-alive',
'Content-Type' : 'application/x-www-form-urlencoded',
'Cookie' : 'ID=201399',
'Host' : 'our_company_page.com',
'Origin' : 'http://our_company_page.com',
'Referer' : 'http://our_company_page.com/adm/add_form.php',
'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, '
'like Gecko) Chrome/26.0.1410.43 Safari/537.31'
}
data = urllib.urlencode(values)
req = urllib2.Request(url, data, headers)
response = urllib2.urlopen(req)
print response.read()
如您所见,我在urllib2
中将Chrome的网络选项卡中的标题添加到POST请求中
Mechanize版本的另一个变化是,我现在通过向请求中添加相关cookie直接访问add_form.php
页面
然而,即使尽我所能复制,我仍然有完全相同的问题:响应与我开始的页面完全相同--没有错误,没有成功消息,服务器上没有更改,只是返回到一个空白表单
最后一步:在绝望中,我安装WireShark
是时候做一些交通嗅探了。我决心在这个神奇的帖子请求中看到WTF的进展
我下载、安装并启动Wireshark。我过滤http
,然后首先在浏览器中手动提交表单,然后运行代码并尝试以编程方式提交表单
这是网络流量:
浏览器:
蟒蛇:
除了标题的顺序稍有不同(这有关系吗),它们看起来完全一样
这就是我所处的位置,我完全不明白为什么一个与浏览器发出的请求几乎相同的post
请求没有在服务器上进行任何更改
有人遇到过这样的事情吗?我错过了什么明显的东西吗?这是怎么回事
编辑 根据Ric的建议,我准确地复制了
POST
数据。我直接从Chrome的“网络源”选项卡复制它
修改后的代码如下所示
data = 'SegmentID=&Segment=FROMPYTHON&SegmentPosition=1&SegmentContains=Sections&fsubmit=Save+Page'
req = urllib2.Request(url, data, headers)
response = urllib2.urlopen(req)
print response.read()
我唯一更改的是段
值,从从浏览器
更改为从Python
不幸的是,这仍然会产生相同的结果。回复是同一页,我从
更新
工作,但没有解决 我检查了
请求
库,使用它们的API复制了我的工作,然后神奇地工作了!这封信实际上通过了。问题仍然是:为什么!?我再次用wireshark拍摄了另一张快照,据我所知,这张快照与浏览器上的帖子完全相同
代码
Wireshark输出
请求 浏览器 所以,总结一下问题的现状。这是可行的,但我觉得没有什么真正的改变。我不知道为什么对Mechanize和urllib2的尝试都失败了。是什么使得
请求
帖子能够真正通过
编辑——王永堂建议:
在Wing Tand Wongs
的建议下,我创建了一个cookie处理程序,并将其附加到urlib.opener
。因此,不再在标头中手动发送更多cookie——事实上,我现在根本不分配任何内容
我首先连接到adm页面,其中包含指向表单的链接,而不是立即连接到表单
'http://my_web_page.com/adm/segments.php?&n=201399'
这将ID
cookie提供给我的urllib
cookieJar
。从这一点上,我跟随链接到该页面
def post(eventID, name, pos, containsID):
segmentContains = ["Sections", "Products"]
url = 'http://my_site.com/adm/add_page.php'
cookies = dict(EventID=str(eventID))
payload = { "SegmentID" : "",
"FormNumber" : name,
"RevisionNumber" : str(pos),
"FormType" : containsID,
"fsubmit" : "Save Page"
}
r = requests.post(
url,
auth=(auth.username, auth.password),
allow_redirects=True,
cookies=cookies,
data=payload)
'http://my_web_page.com/adm/segments.php?&n=201399'
url = 'http://my_web_page.com/adm/segments.php?&n=201399'
post_url = 'http://my_web_page.com/adm/add_page.php'
values = {
'SegmentID':'',
'Segment':'FROM_PYTHON1030PM',
'SegmentPosition':'5',
'SegmentContains':'Products',
'fsubmit':'Save Page'
}
username = auth.username
password = auth.password
headers = {
'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Charset' : 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
'Accept-Encoding' : 'gzip,deflate,sdch',
'Accept-Language' : 'en-US,en;q=0.8',
'User-Agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
'Authorization': 'Basic %s' % base64.encodestring('%s:%s' % (username, password)),
'Cache-Control' : 'max-age=0',
'Connection' : 'keep-alive',
'Content-Type' : 'application/x-www-form-urlencoded',
'Host' : 'mt_site.com',
'Origin' : 'http://my_site.com',
'Referer' : 'http://my_site.com/adm/add_page.php',
'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31'
}
COOKIEFILE = 'cookies.lwp'
cj = cookielib.LWPCookieJar()
if os.path.isfile(COOKIEFILE):
cj.load(COOKIEFILE)
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
urllib2.install_opener(opener)
data = urllib.urlencode(values)
req = urllib2.Request(url, headers=headers)
handle = urllib2.urlopen(req)
req = urllib2.Request(post_url, data, headers)
handle = urllib2.urlopen(req)
print handle.info()
print handle.read()
print
if cj:
print 'These are the cookies we have received so far :'
for index, cookie in enumerate(cj):
print index, ' : ', cookie
cj.save(COOKIEFILE)
These are the cookies we have received so far :
<Cookie EventID=201399 for my_site.com/adm>
password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, gh_url, 'user', 'pass')
auth_manager = urllib2.HTTPBasicAuthHandler(password_manager)
opener = urllib2.build_opener(auth_manager)