4

问题

我有以下问题:我需要使用以下链接搜索有关公司的一些信息。

我需要做的search by entity namesearch type“开始”下拉值。我还希望在该Display number of items to view部分中每页看到“所有项目”。例如,如果我在“输入名称”文本框中输入“google”,脚本应该返回名称以“google”开头的公司列表(尽管这只是我想要做的事情的起点)

问题: 我应该如何使用 Python 来做到这一点?我找到了以下线程:Using Python to ask a web page to run a 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

上面的代码有效,因为UniPort网站包含analytics,它采用这些参数。但是,我使用的网站没有。

我也尝试做与此线程中的第一个答案相同的事情:如何在 python 中将查询提交到 .aspx 页面

但是,第一个答案中提供的示例代码在我的机器上不起作用(Ubuntu 12.4 with Python 2.7)。我也不清楚应该有哪些值,因为我正在处理不同的 aspx 网站。

我如何使用 Python 以某些条件开始搜索 (不确定这是正确的网络术语,可能是提交表单?)

我来自 C++ 背景,没有做任何网络工作。我也在学习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,所以有这些长__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()获取所有s。<input>注意也有<select>s,我只会对它们进行硬编码。

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自己让别人喜欢等。

有时,网站需要更多信息来验证查询。到那时,您可以添加一些自定义标题,如Origin, RefererUser-Agent来模仿浏览器。

而如果网站使用 JavaScript 生成表单,则需要的不仅仅是requests. PhantomJS是制作浏览器脚本的好工具。如果您想在 Python 中执行此操作,可以使用PyQtwith qtwebkit

更新:该网站似乎在昨天之后阻止了我们的 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 回答