mechanize可以支持ajax/通过javascript填写表单吗?

2024-10-01 07:17:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试创建一个程序来填写此网站上的表格: Insurance survey

在多次尝试使用3.4之后,我使用了Python2.7和mechanize,并意识到mechanize在3.4中不起作用。我是一个新手,但是在尝试这样做的过程中我学到了很多东西(python很棒)。在

import mechanize
br = mechanize.Browser() 
urlofmypage = 'https://interactive.web.insurance.ca.gov/survey/'
br.open(urlofmypage) 
print br.geturl()
br.select_form(nr=0)

br['location'] = ['ALAMEDA BERKELEY']   #SET FORM ENTRIES
br['coverageType'] = ['HOMEOWNERS']
br['coverageAmount'] = ['$150,000']
br['homeAge'] = ['1-3 Years']

result = br.submit()
print result

这是我的错误:机械化_form.ItemNotFoundError:名称为“$150000”的项目不足

问题是,只有在我填写完表单字段location和coverageType之后,coverageAmount的选项才会显示出来:(。我一直在搞这个,在网上看了很多视频,我所有的研究都让我得出结论:mechanize不会这样做。在

ajax也没法用。事情似乎指向selenium webdriver。。。有人有什么意见吗?在


Tags: br程序form网站locationresultsurvey表格
3条回答

该页面没有进行AJAX调用。这是一个简单的Javascript代码,从“typeofcoverage:”选择框的onchange事件执行。在

如果您查看页面的源代码,您将看到所有值都存储在Javascript函数coverageTypeOnChange()中。从中你可以找出所有案例的帖子。只要这些值不变,您就可以在不运行Javascript代码的情况下自动抓取站点。在

但是,如果这些值随时间而变化(例如溢价通常是这样),那么您最好还是看看Selenium或其他无头浏览器。在

这个问题曾经让我头疼。关于以下线路:

br['location'] = ['ALAMEDA BERKELEY']   #SET FORM ENTRIES

这意味着您正在从列表中选择“ALAMEDA BERKELEY”。如果是,请尝试在项目后添加逗号:

^{pr2}$

否则使用:

^{3}$

对于机械化问题,我经常尝试精心设计的解决方法,结果回到了我的原始代码并做了一些小小的修改。。。非常强大,非常无情

AJAX调用由javascript执行,mechanize没有办法运行javascript。Mechanize只查看静态HTML页面上的表单字段,并允许您填写和提交这些字段。这就是为什么你的研究将你指向像Selenium或Ghost这样的东西,它们运行在可以执行javascript的真正浏览器之上。在

不过,有一个更简单的方法来做到这一点!如果您在浏览器上使用开发人员工具(例如Firefox或Chrome中的“网络”选项卡)并填写表格,您可以看到您的浏览器在后台发出的请求,即使使用AJAX:

Network tab in Firefox

这告诉你:

  • 浏览器发出了POST请求
  • 指向此URL:https://interactive.web.insurance.ca.gov/survey/survey?type=homeownerSurvey&event=HOMEOWNERS
  • 具有以下形式参数:
    • 位置=ALAMEDA+ALAMEDA
    • coverageType=房主
    • 覆盖量=150000
    • homeAge=新的

您可以使用以下信息在Python中发出相同的POST请求:

import urllib.parse, urllib.request

url = "https://interactive.web.insurance.ca.gov/survey/survey?type=homeownerSurvey&event=HOMEOWNERS"
data = urllib.parse.urlencode(dict(
    location="ALAMEDA ALAMEDA",
    coverageType="HOMEOWNERS",
    coverageAmount="150000",
    homeAge="New",
))
res = urllib.request.urlopen(URL, data.encode("utf8"))

print(res.read())

这是Python3。requests库为发出HTTP请求提供了更好的API。在


编辑:针对您的三个问题:

is it possible for the dictionary that you've created to have more than 1 location and cycle through them using a for loop?

是的,只需在代码周围添加一个循环,并每次为location传递一个不同的值。我会将此代码放入一个函数中,以使代码更干净,如下所示:

https://gist.github.com/lost-theory/08786e3a27c8d8ce3839

the results are in a lot of jibberish, so I'd have to find a way to sift through it huh. Like pick out which is which

是的,jibberish是HTML,您需要解析它来收集您要查找的数据。看看python标准库中的HTMLParser,或者安装一个像lxml或{a7}这样的库,它们有一个更好的API。您也可以尝试使用str.split手动解析文本。在

如果要将表的行转换为pythonlist,则需要查找所有行,如下所示:

^{pr2}$

{{{cd6>在每一行中清除所有元素(cd6}),然后清除这些元素。在

关于StackOverflow有很多问题,还有关于如何用python解析或抓取HTML的教程,比如this或{a9}。在

could you explain why we had to do the data.encode line

当然!在documentation for ^{}中,它说:

data must be a bytes object specifying additional data to be sent to the server, or None if no such data is needed.

urlencode函数返回一个unicode字符串,如果我们试图将其传递到urlopen,则会出现以下错误:

^{3}$

所以我们使用data.encode('utf8')将unicode字符串转换为字节。您通常需要使用字节进行输入和输出,如读取或写入磁盘上的文件,通过网络发送或接收数据,如HTTP请求等。This presentation对python中的字节与unicode字符串有很好的解释,以及为什么在执行I/O时需要解码/编码

相关问题 更多 >