python mechanize 跟随链接失败

3 投票
1 回答
1146 浏览
提问于 2025-04-16 16:49

我正在尝试在一个脚本中访问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中)。我哪里做错了,怎样才能访问到第二页及后面的页面呢?

1 个回答

6

很遗憾,这个页面使用了Javascript来发送2459字节的表单数据到服务器,仅仅是为了跳转到下一个页面。这里有一些变量(我总共数了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请求,发送这些变量中的一些或全部到服务器。幸运的是,如果你能让第二页正常工作,你只需增加一下CurrPage的值,然后再发送一个POST请求,就能获取后续的每一页结果(不需要提取链接)。

更新 - 这个网站真是让人头疼,不过这里有一个基于POST的抓取方法,可以获取2-N页的数据。把MAX_PAGE设置为最高页码加1。这个脚本会生成像file_000003.html这样的文件。

注意:在使用之前,你需要把POSTDATA替换成这个链接中的内容(它会在一个月后过期)。这只是一个POST请求的内容,是通过Firebug捕获的,我用它来设置正确的参数:

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())

撰写回答