python 中用于动态表单的网络抓取工具

Web Scraper for dynamic forms in python

我正在尝试填写此网站的表格 http://www.marutisuzuki.com/Maruti-Price.aspx

它由三个下拉列表组成。一是汽车型号,二是州,三是城市。前两个是静态的,第三个,城市是根据州的值动态生成的,有一个 onclick java 脚本事件 运行 获取州中相应城市的值。

我熟悉 python 中的 mechanize 模块。我遇到了几个 link 告诉我无法在 mechanize 中处理 动态内容。但是这个 link http://toddhayton.com/2014/12/08/form-handling-with-mechanize-and-beautifulsoup/ 在“Adding item dynamically”一节中指出我可以使用 mechanize 来处理动态内容,但我不理解这行代码它

item = Item(br.form.find_control(name='searchAuxCountryID'),{'contents': '3', 'value': '3', 'label': 3})

这行代码中的"Item"是什么,对应的是表格中的city字段。我遇到了 selenium 模块,它可以帮助我处理动态下拉列表。但是我无法在其文档或任何关于如何使用它的好博客中找到任何内容。

有人可以建议我如何针对不同型号、州和城市提交此表格吗?任何关于如何解决此问题的 link 将不胜感激。 python 中有关如何提交表单的示例代码会有所帮助。提前致谢。

如果您在开发人员工具中查看发送到该站点的请求,您会看到 POST 在您 select 状态后立即发送。发回的响应具有填充了城市下拉列表中的值的表单。

因此,要在您的脚本中复制它,您需要如下内容:

  • 打开页面
  • Select表格
  • Select 模型和状态的值
  • 提交表格
  • Select 发回的响应中的表单
  • Select 城市值(现在应该填充)
  • 提交表格
  • 解析 table 个结果的响应

看起来像这样:

#!/usr/bin/env python                                                                                                                                                                

import re
import mechanize

from bs4 import BeautifulSoup

def select_form(form):
    return form.attrs.get('id', None) == 'form1'

def get_state_items(browser):
    browser.select_form(predicate=select_form)
    ctl = browser.form.find_control('ctl00$ContentPlaceHolder1$ddlState')
    state_items = ctl.get_items()
    return state_items[1:]

def get_city_items(browser):
    browser.select_form(predicate=select_form)
    ctl = browser.form.find_control('ctl00$ContentPlaceHolder1$ddlCity')
    city_items = ctl.get_items()
    return city_items[1:]

br = mechanize.Browser()
br.open('http://www.marutisuzuki.com/Maruti-Price.aspx')    
br.select_form(predicate=select_form)
br.form['ctl00$ContentPlaceHolder1$ddlmodel'] = ['AK'] # model = Maruti Suzuki Alto K10                                                                                              

for state in get_state_items(br):
    # 1 - Submit form for state.name to get cities for this state                                                                                                                    
    br.select_form(predicate=select_form)
    br.form['ctl00$ContentPlaceHolder1$ddlState'] = [ state.name ]
    br.submit()

    # 2 - Now the city dropdown is filled for state.name                                                                                                                             
    for city in get_city_items(br):
        br.select_form(predicate=select_form)
        br.form['ctl00$ContentPlaceHolder1$ddlCity'] = [ city.name ]
        br.submit()

        s = BeautifulSoup(br.response().read())
        t = s.find('table', id='ContentPlaceHolder1_dtDealer')
        r = re.compile(r'^ContentPlaceHolder1_dtDealer_lblName_\d+$')

        header_printed = False
        for p in t.findAll('span', id=r):
            tr = p.findParent('tr')
            td = tr.findAll('td')

            if header_printed is False:
                str = '%s, %s' % (city.attrs['label'], state.attrs['label'])
                print str
                print '-' * len(str)
                header_printed = True

            print ' '.join(['%s' % x.text.strip() for x in td])

我在教程中遇到了同样的问题,这对我有用:

item = mechanize.Item(br.form.find_control(name='searchAuxCountryID'),{'contents': '3', 'value': '3', 'label': 3})