【问题标题】:python mechanize follow_link failspython mechanize follow_link 失败
【发布时间】:2011-05-02 16:07:55
【问题描述】:

我正在尝试通过脚本访问 NCBI 图像搜索页面 (http://www.ncbi.nlm.nih.gov/images) 上的搜索结果。我想给它一个搜索词,报告所有结果,然后继续下一个搜索词。为此,我需要在第一页之后进入结果页面,因此我尝试使用 python mechanize 来做到这一点:

import mechanize
browser=mechanize.Browser()
page1=browser.open('http://www.ncbi.nlm.nih.gov/images?term=drug')
a=browser.links(text_regex='Next')
nextlink=a.next()
page2=browser.follow_link(nextlink)

这只是让我再次返回搜索结果的第一页(在变量 page2 中)。我做错了什么,我怎样才能到达第二页及以后?

【问题讨论】:

    标签: python hyperlink mechanize


    【解决方案1】:

    不幸的是,该页面使用 Javascript 将 2459 字节的表单变量 POST 到服务器,只是为了导航到后续页面。以下是一些变量(我总共计算了 38 个变量):

    EntrezSystem2.PEntrez.ImagesDb.Images_SearchBar.Term=drug
    EntrezSystem2.PEntrez.ImagesDb.Images_SearchBar.CurrDb=images
    EntrezSystem2.PEntrez.ImagesDb.Images_ResultsPanel.Entrez_Pager.CurrPage=2
    

    您需要向包含部分或全部这些变量的服务器构造一个 POST 请求。幸运的是,如果你让它在第 2 页上工作,你可以简单地增加 CurrPage 并发送另一个 POST 来获取每个后续​​页面的结果(无需提取链接)。

    更新 - 该网站是一个彻头彻尾的痛苦,但这里是 2-N 个页面的基于 POST 的抓取。将MAX_PAGE设置为最高页码+1。脚本将生成file_000003.html之类的文件。

    注意:使用前需要将POSTDATA替换为contents of this paste blob(1个月后失效)。它只是 Firebug 捕获的 POST 请求的主体,我用它来播种正确的参数:

    import cookielib
    import json
    import mechanize
    import sys
    import urllib
    import urlparse
    
    MAX_PAGE = 6
    TERM = 'drug'
    DEBUG = False
    
    base_url = 'http://www.ncbi.nlm.nih.gov/images?term=' + TERM
    browser = mechanize.Browser()
    browser.set_handle_robots(False)
    browser.set_handle_referer(True)
    browser.set_debug_http(DEBUG)
    browser.set_debug_responses(DEBUG)
    cjar = cookielib.CookieJar()
    browser.set_cookiejar(cjar)
    
    # make first GET request. this will populate the cookie
    res = browser.open(base_url)
    
    def write(num, data):
        with open('file_%06d.html' % num, 'wb') as out:
            out.write(data)
    
    def encode(kvs):
        res = []
        for key, vals in kvs.iteritems():
            if isinstance(vals, list):
                for v in vals:
                    res.append('%s=%s' % (key, urllib.quote(v)))
            else:
                res.append('%s=%s' % (key, urllib.quote(vals)))
        return '&'.join(res)
    
    write(1, res.read())
    
    # set this var equal to the contents of this: http://pastebin.com/UfejW3G0
    POSTDATA = '''<post data>'''
    
    # parse the embedded json vars into POST parameters
    PREFIX1 = 'EntrezSystem2.PEntrez.ImagesDb.'
    PREFIX2 = 'EntrezSystem2.PEntrez.DbConnector.'
    params = dict((k, v[0]) for k, v in urlparse.parse_qs(POSTDATA).iteritems())
    
    base_url = 'http://www.ncbi.nlm.nih.gov/images'
    for page in range(2, MAX_PAGE):
        params[PREFIX1 + 'Images_ResultsPanel.Entrez_Pager.CurrPage'] = str(page)
        params[PREFIX1 + 'Images_ResultsPanel.Entrez_Pager.cPage'] = [str(page-1)]*2
    
        data = encode(params)
        req = mechanize.Request(base_url, data)
        cjar.add_cookie_header(req)
        req.add_header('Content-Type', 'application/x-www-form-urlencoded')
        req.add_header('Referer', base_url)
        res = browser.open(req)
    
        write(page, res.read())
    

    【讨论】:

    • 感谢您的帮助。我不知道任何 Javascript,所以我可以使用 mechanize 提供的一些 POST 功能还是需要在 Javascript 中做一些事情?
    • 顺便说一句,我之前尝试过使用 wget 和 curl 与这些变量的 POST 数据一起使用,并且得到了基本相同的行为:无论我通过什么 CurrPage 编号,总是只获得结果的第一页。令人困惑。
    • 您可以从 mechanize 提交 POST。您尝试抓取的网站正在做一些疯狂的事情,因此可能需要准确确定需要提交哪些变量。如果有帮助,我将通过一个使用 mechanize 进行 POST 的示例来更新我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-14
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 1970-01-01
    • 2016-01-17
    相关资源
    最近更新 更多