【问题标题】:how to submit query to .aspx page in python如何在python中向.aspx页面提交查询
【发布时间】:2010-12-01 14:37:03
【问题描述】:

我需要从 .aspx 网页中抓取查询结果。

http://legistar.council.nyc.gov/Legislation.aspx

url 是静态的,那么如何向这个页面提交查询并获得结果呢?假设我们需要从相应的下拉菜单中选择“所有年份”和“所有类型”。

一定有人知道如何做到这一点。

【问题讨论】:

    标签: asp.net python asp.net-ajax


    【解决方案1】:

    作为概述,您将需要执行四项主要任务:

    • 向网站提交请求,
    • 从站点检索响应
    • 解析这些响应
    • 在上述任务中迭代一些逻辑,并带有与导航关联的参数(到结果列表中的“下一个”页面)

    http 请求和响应处理是使用 Python 标准库的 urlliburllib2 中的方法和类完成的。 html页面的解析可以通过Python的标准库HTMLParser或者Beautiful Soup等其他模块完成

    以下 sn-p 演示了在问题中指示的站点上请求和接收搜索。该站点是 ASP 驱动的,因此我们需要确保发送多个表单字段,其中一些具有“可怕”值,因为 ASP 逻辑使用这些字段来维护状态并在某种程度上验证请求。确实提交。必须使用 http POST 方法 发送请求,因为这是该 ASP 应用程序所期望的。主要困难在于识别 ASP 期望的表单字段和相关值(使用 Python 获取页面是容易的部分)。

    这段代码是功能性的,或者更准确地说,功能性的,直到我删除了大部分 VSTATE 值,并且可能通过添加 cmets 引入了一两个错字。

    import urllib
    import urllib2
    
    uri = 'http://legistar.council.nyc.gov/Legislation.aspx'
    
    #the http headers are useful to simulate a particular browser (some sites deny
    #access to non-browsers (bots, etc.)
    #also needed to pass the content type. 
    headers = {
        'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13',
        'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml; q=0.9,*/*; q=0.8',
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    
    # we group the form fields and their values in a list (any
    # iterable, actually) of name-value tuples.  This helps
    # with clarity and also makes it easy to later encoding of them.
    
    formFields = (
       # the viewstate is actualy 800+ characters in length! I truncated it
       # for this sample code.  It can be lifted from the first page
       # obtained from the site.  It may be ok to hardcode this value, or
       # it may have to be refreshed each time / each day, by essentially
       # running an extra page request and parse, for this specific value.
       (r'__VSTATE', r'7TzretNIlrZiKb7EOB3AQE ... ...2qd6g5xD8CGXm5EftXtNPt+H8B'),
    
       # following are more of these ASP form fields
       (r'__VIEWSTATE', r''),
       (r'__EVENTVALIDATION', r'/wEWDwL+raDpAgKnpt8nAs3q+pQOAs3q/pQOAs3qgpUOAs3qhpUOAoPE36ANAve684YCAoOs79EIAoOs89EIAoOs99EIAoOs39EIAoOs49EIAoOs09EIAoSs99EI6IQ74SEV9n4XbtWm1rEbB6Ic3/M='),
       (r'ctl00_RadScriptManager1_HiddenField', ''), 
       (r'ctl00_tabTop_ClientState', ''), 
       (r'ctl00_ContentPlaceHolder1_menuMain_ClientState', ''),
       (r'ctl00_ContentPlaceHolder1_gridMain_ClientState', ''),
    
       #but then we come to fields of interest: the search
       #criteria the collections to search from etc.
                                                           # Check boxes  
       (r'ctl00$ContentPlaceHolder1$chkOptions$0', 'on'),  # file number
       (r'ctl00$ContentPlaceHolder1$chkOptions$1', 'on'),  # Legislative text
       (r'ctl00$ContentPlaceHolder1$chkOptions$2', 'on'),  # attachement
                                                           # etc. (not all listed)
       (r'ctl00$ContentPlaceHolder1$txtSearch', 'york'),   # Search text
       (r'ctl00$ContentPlaceHolder1$lstYears', 'All Years'),  # Years to include
       (r'ctl00$ContentPlaceHolder1$lstTypeBasic', 'All Types'),  #types to include
       (r'ctl00$ContentPlaceHolder1$btnSearch', 'Search Legislation')  # Search button itself
    )
    
    # these have to be encoded    
    encodedFields = urllib.urlencode(formFields)
    
    req = urllib2.Request(uri, encodedFields, headers)
    f= urllib2.urlopen(req)     #that's the actual call to the http site.
    
    # *** here would normally be the in-memory parsing of f 
    #     contents, but instead I store this to file
    #     this is useful during design, allowing to have a
    #     sample of what is to be parsed in a text editor, for analysis.
    
    try:
      fout = open('tmp.htm', 'w')
    except:
      print('Could not open output file\n')
    
    fout.writelines(f.readlines())
    fout.close()
    

    这就是获取初始页面的内容。如上所述,然后需要解析页面,即找到感兴趣的部分并酌情收集它们,并将它们存储到文件/数据库/任何地方。这项工作可以通过多种方式完成:使用 html 解析器,或 XSLT 类型的技术(实际上是在将 html 解析为 xml 之后),甚至对于粗略的工作,简单的正则表达式。此外,通常提取的项目之一是“下一个信息”,即各种链接,可用于对服务器的新请求以获取后续页面。

    这应该让您大致了解“长手” html 抓取的内容。还有很多其他方法可以解决这个问题,例如专用实用程序、Mozilla (FireFox) GreaseMonkey 插件中的脚本、XSLT...

    【讨论】:

    • 如果我使用的是谷歌浏览器,那么我应该如何替换“HTTP_USER_AGENT”的值?如果这个问题很愚蠢,我很抱歉,因为我没有做太多网络工作。谢谢!
    • @taocp,了解给定浏览器使用什么HTTP_USER_AGENT 字符串的简单方法是访问all-nettools.com/toolbox/environmental-variables-test.php 此页面将显示浏览器发送的标头值,查找“HTTP_USER_AGENT ”。实际字符串取决于操作系统和特定版本以及 Chrome 的构建,但应该看起来像 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36
    • 非常感谢您的回复。我尝试了为我的 chrome 浏览器设置了正确值的代码。结果 tmp.htm 文件显示“未找到结果”,而当我将“york”放在网站本身时,它返回了很多。你知道为什么吗?
    • @mjv 我有一个类似的问题。但我仍然无法遵循这些概念。我的线程在这里stackoverflow.com/questions/32638741/…。如果你能帮助我。我会很感激的,这已经困扰了我一段时间了
    • 谁能详细说明如何使用 Python requests 模块做到这一点?我觉得这样会容易得多......
    【解决方案2】:

    大多数 ASP.NET 站点(包括您引用的站点)实际上会使用 HTTP POST 动词而不是 GET 动词将它们的查询发回给它们自己。这就是为什么 URL 没有像你所说的那样改变。

    您需要做的是查看生成的 HTML 并捕获它们的所有表单值。请务必捕获所有表单值,因为其中一些用于页面验证,如果没有它们,您的 POST 请求将被拒绝。

    除了验证之外,ASPX 页面在抓取和发布方面与其他网络技术没有什么不同。

    【讨论】:

      【解决方案3】:

      Selenium 是用于此类任务的绝佳工具。您可以指定要输入的表单值,并在几行 python 代码中将响应页面的 html 检索为字符串。 使用 Selenium,您可能不必手动模拟有效的发布请求及其所有隐藏变量,正如我在经过多次试验和错误后发现的那样。

      【讨论】:

      • 我成功地使用 selenium 连接、登录和单击链接我被困在要从页面中获取数据的部分。由于即使点击后 URI 也保持不变,这会带来问题。
      【解决方案4】:

      其他答案中的代码很有用;没有它,我永远无法编写我的爬虫。

      我确实遇到的一个问题是 cookie。我正在爬取的网站使用 cookie 来记录会话 ID/安全信息,因此我必须添加代码才能让我的爬虫工作:

      添加这个导入:

          import cookielib            
      

      初始化 cookie 内容:

          COOKIEFILE = 'cookies.lwp'          # the path and filename that you want to use to save your cookies in
          cj = cookielib.LWPCookieJar()       # This is a subclass of FileCookieJar that has useful load and save methods
      

      安装CookieJar,使其在默认开启程序处理程序中用作默认CookieProcessor

          cj.load(COOKIEFILE)
          opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
          urllib2.install_opener(opener)
      

      要查看网站正在使用哪些 cookie:

          print 'These are the cookies we have received so far :'
      
          for index, cookie in enumerate(cj):
              print index, '  :  ', cookie        
      

      这会保存 cookie:

          cj.save(COOKIEFILE)                     # save the cookies 
      

      【讨论】:

        【解决方案5】:

        “假设我们需要从相应的下拉菜单中选择“所有年份”和“所有类型”。”

        这些选项对最终提交的 URL 有什么作用。

        毕竟,它相当于通过urllib2 发送的HTTP 请求。

        知道如何从相应的下拉菜单中执行“所有年份”和“所有类型”,然后执行以下操作。

        1. 从相应的下拉菜单中选择“所有年份”和“所有类型”

        2. 注意实际提交的URL。

        3. urllib2 中使用此网址。

        【讨论】:

        • 显然该页面是一个需要 POST 的表单,但想法是相同的:记下表单字段名称和与“所有年份”关联的值和“所有类型”并使用 urlib2 .请求获取数据。
        • 当我浏览这个网站并提交查询时,我正在使用 Charles Web 调试代理来查看所有的 http 流量,并且 url 是完全静态的。它根本不包含任何参数。有表单数据要以某种方式传递——我猜是 ajax——但我不知道如何将该表单数据提交到服务器。这一切在我看来都难以理解。我无法通过操纵 url 来提交查询这一事实让我感到困惑。
        • 一旦你从这个页面得到结果,如果你想scarpe它,你可以使用python模块HTMLParser或Beautifulsoup来解析html页面。此外,抓取可能会涉及更多 urllib2 调用以导航到结果的下一页。
        猜你喜欢
        • 2011-01-04
        • 1970-01-01
        • 1970-01-01
        • 2011-09-10
        • 1970-01-01
        • 1970-01-01
        • 2020-01-26
        • 2014-06-21
        • 1970-01-01
        相关资源
        最近更新 更多