web-dev-qa-db-ja.com

python)の.aspxページにクエリを送信する方法

.aspxWebページからクエリ結果を取得する必要があります。

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

URLは静的ですが、このページにクエリを送信して結果を取得するにはどうすればよいですか?それぞれのドロップダウンメニューから「すべての年」と「すべてのタイプ」を選択する必要があると仮定します。

そこにいる誰かがこれを行う方法を知っている必要があります。

22
twneale

概要として、次の4つの主要なタスクを実行する必要があります。

  • webサイトにリクエストを送信するには、
  • サイトから応答を取得するには
  • これらの応答を解析するには
  • (結果リストの「次の」ページへの)ナビゲーションに関連付けられたパラメーターを使用して、上記のタスクを反復するロジックを用意する

Httpの要求と応答の処理は、Pythonの標準ライブラリの rllib および rllib2 のメソッドとクラスを使用して行われます。 HTMLページの解析は、Pythonの標準ライブラリ HTMLParser または Beautiful Soup などの他のモジュールを使用して実行できます。

次のスニペットは、質問で示されたサイトでの検索の要求と受信を示しています。このサイトはASP主導型であるため、いくつかのフォームフィールドを送信する必要があります。これらのフォームフィールドの一部は、ASPロジックによって使用され、状態を維持し、リクエストを認証します。ある程度。確かに提出します。リクエストはhttp POSTメソッドで送信する必要があります。これは、このASPアプリケーションから期待されるものだからです。主な問題は、ASPが期待するフォームフィールドと関連する値を特定することです(Pythonでページを取得するのは簡単です)。

このコードは機能します。より正確には、VSTATE値のほとんどを削除し、コメントを追加してタイプミスを1つか2つ導入するまで、は機能していました

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に解析した後)を使用するか、粗雑なジョブの場合でも単純な正規表現を使用します。また、通常抽出される項目の1つは「次の情報」、つまり、サーバーへの新しい要求で後続のページを取得するために使用できる種類のリンクです。

これにより、「ロングハンド」のhtmlスクレイピングが何であるかを大まかに把握できます。これには、専用ユーティリティ、Mozilla(FireFox)のGreaseMonkeyプラグインのスクリプト、XSLTなど、他にも多くのアプローチがあります。

28
mjv

Selenium は、この種のタスクに使用するのに最適なツールです。入力するフォーム値を指定して、応答ページのhtmlを文字列としてpythonコード)の数行で取得できます。Seleniumを使用すると、手動で行う必要がない場合があります。多くの試行錯誤の末にわかったように、有効なPOSTリクエストとそのすべての隠れた変数をシミュレートする作業。

5
user773328

他の回答のコードは役に立ちました。それなしではクローラーを書くことはできなかったでしょう。

私が遭遇した問題の1つは、Cookieでした。私がクロールしていたサイトは、Cookieを使用してセッションID /セキュリティ関連のものをログに記録していたため、クローラーを機能させるためにコードを追加する必要がありました。

このインポートを追加します:

    import cookielib            

クッキーのものを初期化します:

    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
bill smith

ほとんどのASP.NETサイト(参照したサイトを含む)は、実際にはGET動詞ではなくHTTP POST動詞)を使用してクエリを自分自身にポストバックします。そのため、URLは変更されません。了解しました。

あなたがする必要があるのは、生成されたHTMLを見て、それらのすべてのフォーム値をキャプチャすることです。一部のフォーム値はページ検証に使用され、それらがないとPOSTリクエストが拒否されるため、必ずすべてのフォーム値をキャプチャしてください。

検証を除いて、スクレイピングと投稿に関するASPXページは他のWebテクノロジーと同じです。

4
Jason Whitehorn

「それぞれのドロップダウンメニューから「すべての年」と「すべてのタイプ」を選択する必要があると仮定します。」

これらのオプションは、最終的に送信されるURLに対して何をしますか。

結局のところ、それはurllib2を介して送信されるHTTPリクエストに相当します。

それぞれのドロップダウンメニューから「すべての年」と「すべてのタイプ」を実行する方法を知っていますか?次のようにします。

  1. それぞれのドロップダウンメニューから「すべての年」と「すべてのタイプ」を選択します。

  2. 実際に送信されたURLに注意してください。

  3. このURLをurllib2で使用します。

0
S.Lott