4

問題

次の質問があります。次のリンクを使用して会社に関する情報を検索する必要があります。

私がそれを行う必要があるのは、search by entity namesearch type開始」ドロップダウン値であることです。Display number of items to viewまた、その部分でページごとに「すべてのアイテム」を表示したいと思います。たとえば、「名前を入力してください」テキスト ボックスに「google」と入力すると、スクリプトは「google」で始まる名前の会社のリストを返すはずです (ただし、これは私がやりたいことの出発点にすぎません)

質問: Python を使用してこれを行うにはどうすればよいですか? 次のスレッドを見つけました: Using Python to ask a web page to run search

最初の回答の例を試しました。コードを以下に示します。

from bs4 import BeautifulSoup as BS
import requests

protein='Q9D880'

text = requests.get('http://www.uniprot.org/uniprot/' + protein).text
soup = BS(text)
MGI = soup.find(name='a', onclick="UniProt.analytics('DR-lines', 'click', 'DR-MGI');").text
MGI = MGI[4:]
print protein +' - ' + MGI

上記のコードが機能するのは、これらのパラメーターを受け取る がUniPortWeb サイトに含まれているためです。analyticsしかし、私が使っているウェブサイトにはそれがありません。

また、このスレッドの最初の回答と同じことを試みました: how to submit query to .aspx page in python

ただし、最初の回答で提供されているコード例は、私のマシンでは機能しません(Ubuntu 12.4 with Python 2.7)。別のaspx Webサイトを扱っているため、どの値が必要かについても明確ではありません。

Python を使用して特定の基準で検索を開始するにはどうすればよいです か (これが適切な Web 用語であるかどうかわかりません。フォームを送信する可能性があります)

私は C++ のバックグラウンドを持っており、Web のことは何もしていません。Pythonも学んでいます。どんな助けでも大歓迎です。

最初の編集:
@Kabieの多大な助けを借りて、次のコードを収集しました(それがどのように機能するかを理解しようとしています):

import requests
from lxml import etree

URL = 'http://corp.sec.state.ma.us/CorpWeb/CorpSearch/CorpSearch.aspx'

#With get_fields(), we fetched all <input>s from the form.
def get_fields():
    res = requests.get(URL)
    if res.ok:
        page = etree.HTML(res.text)
        fields = page.xpath('//form[@id="Form1"]//input')
        return { e.attrib['name']: e.attrib.get('value', '') for e in fields }

#hard code some selects from the Form
def query(data):
    formdata = get_fields()
    formdata.update({
        'ctl00$MainContent$ddRecordsPerPage':'25',
    }) # Hardcode some <select> value
    formdata.update(data)
    res = requests.post(URL, formdata)
    if res.ok:
        page = etree.HTML(res.text)
        return page.xpath('//table[@id="MainContent_SearchControl_grdSearchResultsEntity"]//tr')


def search_by_entity_name(entity_name, entity_search_type='B'):
    return query({
        'ctl00$MainContent$CorpSearch':'rdoByEntityName',
        'ctl00$MainContent$txtEntityName': entity_name,
        'ctl00$MainContent$ddBeginsWithEntityName': entity_search_type,
    })

result = search_by_entity_name('google')

上記のコードは、 という名前のスクリプトに入れられquery.pyます。次のエラーが発生しました。

トレースバック (最新の呼び出しが最後): ファイル "query.py"、39 行目、
結果 = search_by_entity_name('google')
ファイル "query.py"、36 行目、search_by_entity_name
'ctl00$MainContent$ddBeginsWithEntityName': entity_search_type、
ファイル「query.py」、行 21、クエリ
formdata.update({
AttributeError: 'NoneType' object has no attribute 'update'

検索がうまくいかないように思えますか?なんで?

4

1 に答える 1

4

ページを調べて、投稿する必要があるすべてのフィールドを見つけることができます。には素敵なチュートリアルがありChrome DevToolsます。FireBugFireFox やDragonFlyOperaなどの他のツールも機能しますが、お勧めしDevToolsます。

クエリを投稿した後。パネルでは、Network実際に送信されたフォームデータを確認できます。この場合:

__EVENTTARGET:
__EVENTARGUMENT:
__LASTFOCUS:
__VIEWSTATE:5UILUho/L3O0HOt9WrIfldHD4Ym6KBWkQYI1GgarbgHeAdzM9zyNbcH0PdP6xtKurlJKneju0/aAJxqKYjiIzo/7h7UhLrfsGul1Wq4T0+BroiT+Y4QVML66jsyaUNaM6KNOAK2CSzaphvSojEe1BV9JVGPYWIhvx0ddgfi7FXKIwdh682cgo4GHmilS7TWcbKxMoQvm9FgKY0NFp7HsggGvG/acqfGUJuw0KaYeWZy0pWKEy+Dntb4Y0TGwLqoJxFNQyOqvKVxnV1MJ0OZ4Nuxo5JHmkeknh4dpjJEwui01zK1WDuBHHsyOmE98t2YMQXXTcE7pnbbZaer2LSFNzCtrjzBmZT8xzCkKHYXI31BxPBEhALcSrbJ/QXeqA7Xrqn9UyCuTcN0Czy0ZRPd2wabNR3DgE+cCYF4KMGUjMUIP+No2nqCvsIAKmg8w6Il8OAEGJMAKA01MTMONKK4BH/OAzLMgH75AdGat2pvp1zHVG6wyA4SqumIH//TqJWFh5+MwNyZxN2zZQ5dBfs3b0hVhq0cL3tvumTfb4lr/xpL3rOvaRiatU+sQqgLUn0/RzeKNefjS3pCwUo8CTbTKaSW1IpWPgP/qmCsuIovXz82EkczLiwhEZsBp3SVdQMqtAVcYJzrcHs0x4jcTAWYZUejvtMXxolAnGLdl/0NJeMgz4WB9tTMeETMJAjKHp2YNhHtFS9/C1o+Hxyex32QxIRKHSBlJ37aisZLxYmxs69squmUlcsHheyI5YMfm0SnS0FwES5JqWGm2f5Bh+1G9fFWmGf2QeA6cX/hdiRTZ7VnuFGrdrJVdbteWwaYQuPdekms2YVapwuoNzkS/A+un14rix4bBULMdzij25BkXpDhm3atovNHzETdvz5FsXjKnPlno0gH7la/tkM8iOdQwqbeh7sG+/wKPqPmUk0Cl0kCHNvMCZhrcgQgpIOOgvI2Fp+PoB7mPdb80T2sTJLlV7Oe2ZqMWsYxphsHMXVlXXeju3kWfpY+Ed/D8VGWniE/eoBhhqyOC2+gaWA2tcOyiDPDCoovazwKGWz5B+FN1OTep5VgoHDqoAm2wk1C3o0zJ9a9IuYoATWI1yd2ffQvx6uvZQXcMvTIbhbVJL+ki4yNRLfVjVnPrpUMjafsnjIw2KLYnR0rio8DWIJhpSm13iDj/KSfAjfk4TMSA6HjhhEBXIDN/ShQAHyrKeFVsXhtH5TXSecY6dxU+Xwk7iNn2dhTILa6S/Gmm06bB4nx5Zw8XhYIEI/eucPOAN3HagCp7KaSdzZvrnjbshmP8hJPhnFhlXdJ+OSYDWuThFUypthTxb5NXH3yQk1+50SN872TtQsKwzhJvSIJExMbpucnVmd+V2c680TD4gIcqWVHLIP3+arrePtg0YQiVTa1TNzNXemDyZzTUBecPynkRnIs0dFLSrz8c6HbIGCrLleWyoB7xicUg39pW7KTsIqWh7P0yOiHgGeHqrN95cRAYcQTOhA==
__SCROLLPOSITIONX:0
__SCROLLPOSITIONY:106
__VIEWSTATEENCRYPTED:
__EVENTVALIDATION:g2V3UVCVCwSFKN2X8P+O2SsBNGyKX00cyeXvPVmP5dZSjIwZephKx8278dZoeJsa1CkMIloC0D51U0i4Ai0xD6TrYCpKluZSRSphPZQtAq17ivJrqP1QDoxPfOhFvrMiMQZZKOea7Gi/pLDHx42wy20UdyzLHJOAmV02MZ2fzami616O0NpOY8GQz1S5IhEKizo+NZPb87FgC5XSZdXCiqqoChoflvt1nfhtXFGmbOQgIP8ud9lQ94w3w2qwKJ3bqN5nRXVf5S53G7Lt+Du78nefwJfKK92BSgtJSCMJ/m39ykr7EuMDjauo2KHIp2N5IVzGPdSsiOZH86EBzmYbEw==
ctl00$MainContent$hdnApplyMasterPageWitoutSidebar:0
ctl00$MainContent$hdn1:0
ctl00$MainContent$CorpSearch:rdoByEntityName
ctl00$MainContent$txtEntityName:GO
ctl00$MainContent$ddBeginsWithEntityName:M
ctl00$MainContent$ddBeginsWithIndividual:B
ctl00$MainContent$txtFirstName:
ctl00$MainContent$txtMiddleName:
ctl00$MainContent$txtLastName:
ctl00$MainContent$txtIdentificationNumber:
ctl00$MainContent$txtFilingNumber:
ctl00$MainContent$ddRecordsPerPage:25
ctl00$MainContent$btnSearch:Search Corporations
ctl00$MainContent$hdnW:1920
ctl00$MainContent$hdnH:1053
ctl00$MainContent$SearchControl$hdnRecordsPerPage:

私が投稿するのはBegin with 'GO'. このサイトは で構築されてWebFormsいるため、これらの longフィールド__VIEWSTATE__EVENTVALIDATIONフィールドがあります。それらも送信する必要があります。

これで、クエリを作成する準備が整いました。まず、空白のフォームを取得する必要があります。次のコードは Python 3.3 で書かれていますが、2.x でも動作するはずです。

import requests
from lxml import etree

URL = 'http://corp.sec.state.ma.us/CorpWeb/CorpSearch/CorpSearch.aspx'

def get_fields():
    res = requests.get(URL)
    if res.ok:
        page = etree.HTML(res.text)
        fields = page.xpath('//form[@id="Form1"]//input')
        return { e.attrib['name']: e.attrib.get('value', '') for e in fields }

では、フォームからget_fields()すべての を取得しました。<input>もあることに注意してください<select>。ハードコーディングします。

def query(data):
    formdata = get_fields()
    formdata.update({
        'ctl00$MainContent$ddRecordsPerPage':'25',
    }) # Hardcode some <select> value
    formdata.update(data)
    res = requests.post(URL, formdata)
    if res.ok:
        page = etree.HTML(res.text)
        return page.xpath('//table[@id="MainContent_SearchControl_grdSearchResultsEntity"]//tr')

これで汎用query関数ができたので、特定の関数のラッパーを作成しましょう。

def search_by_entity_name(entity_name, entity_search_type='B'):
    return query({
        'ctl00$MainContent$CorpSearch':'rdoByEntityName',
        'ctl00$MainContent$txtEntityName': entity_name,
        'ctl00$MainContent$ddBeginsWithEntityName': entity_search_type,
    })

この特定のサンプル サイトでは、使用する<radio>フィールドを決定するために のグループを使用しているため、'ctl00$MainContent$CorpSearch':'rdoByEntityName'ここが必要です。そして、あなたはsearch_by_individual_name自分で他の人などを作ることができます。

場合によっては、Web サイトでクエリを検証するためにより多くの情報が必要になることがあります。それまでに、、、などのカスタム ヘッダーを追加して、ブラウザを模倣することができます。OriginRefererUser-Agent

また、Web サイトが JavaScript を使用してフォームを生成している場合は、requests. PhantomJSは、ブラウザ スクリプトを作成するための優れたツールです。これを Python で行いたい場合は、PyQtwithを使用できますqtwebkit

更新: 昨日以降、Web サイトが Python スクリプトへのアクセスをブロックしたようです。そのため、ブラウザのふりをする必要があります。上で述べたように、カスタム ヘッダーを追加できます。User-Agent最初にヘッダーにフィールドを追加して、何が起こったのか見てみましょう。

res = requests.get(URL, headers={
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36',
})

そして今...res.ok戻りますTrue

したがって、このヘッダーを call res = requests.get(URL)inget_fields()res = requests.post(URL, formdata)inの両方に追加する必要がありquery()ます。念'Referer':URLのため、後者のヘッダーに追加します。

res = requests.post(URL, formdata, headers={
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36',
    'Referer':URL,
})
于 2013-09-19T05:07:56.553 に答える