如何从静态网站启动查询?

时间:2013-09-17 01:53:50

标签: python search python-2.7 web screen-scraping

问题

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

我需要做的是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,其中包含这些参数。但是,我使用的网站没有这个。

我也尝试过与此主题中第一个答案相同的事情:how to submit query to .aspx page in python

但是,第一个答案中提供的示例代码在我的机器(带有Python 2.7的Ubuntu 12.4)上不起作用。由于我正在处理不同的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行,在       result = search_by_entity_name('google')
    在search_by_entity_name中文件“query.py”,第36行       'ctl00 $ MainContent $ ddBeginsWithEntityName':entity_search_type,
    文件“query.py”,第21行,在查询中       formdata.update({
  AttributeError:'NoneType'对象没有属性'update'

在我看来搜索不成功?为什么呢?

1 个答案:

答案 0 :(得分:4)

您可以检查页面以找出需要发布的所有字段。 Chrome DevToolsa nice tutorial。 FireFox上的FireBug或Opera上的DragonFly等其他工具也会在我推荐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(),我们从表单中获取了所有<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等其他人。

有时,网站需要更多信息来验证查询。到那时,您可以添加一些custom headers,例如OriginRefererUser-Agent来模仿浏览器。

如果网站使用JavaScript生成表单,则需要的不仅仅是requestsPhantomJS是制作浏览器脚本的好工具。如果您想在Python中执行此操作,可以将PyQtqtwebkit一起使用。

<强>更新: 看来网站阻止我们的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

因此,我们只需要在res = requests.get(URL)中的get_fields()res = requests.post(URL, formdata)中的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,
})