如何在python中向.aspx页面提交查询

时间:2009-09-26 03:27:23

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

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

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

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

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

5 个答案:

答案 0 :(得分:28)

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

  • 向网站提交请求,
  • 从网站上检索回复
  • 解析这些回复
  • 有一些逻辑来迭代上面的任务,参数与导航相关联(到结果列表中的“下一页”)

http请求和响应处理是使用Python标准库urlliburllib2中的方法和类完成的。可以使用Python的标准库HTMLParser或其他模块(例如Beautiful Soup

)来解析html页面。

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

此代码功能正常,或者更准确地说, 功能正常,直到我删除了大部分VSTATE值,并且可能通过添加注释引入了一两个拼写错误。

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 ......

答案 1 :(得分:5)

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

答案 2 :(得分:4)

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

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

除了验证之外,关于抓取和发布的ASPX页面与其他Web技术没有什么不同。

答案 3 :(得分:4)

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

我遇到的一个问题是cookies。我抓取的网站使用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 

答案 4 :(得分:0)

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

这些选项对最终提交的网址有何作用。

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

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

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

  2. 请注意实际提交的网址。

  3. urllib2

  4. 中使用此网址