2011-05-02 75 views
2

我試圖在腳本中訪問NCBI圖像搜索頁面(http://www.ncbi.nlm.nih.gov/images)上的搜索結果。我想爲它提供一個搜索詞,報告所有結果,然後轉到下一個搜索詞。要做到這一點,我需要去的第一頁之後的結果頁面,所以我想使用Python機械化做到這一點:python機械化關注鏈接失敗

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) 

這只是給我回的搜索結果的第一頁再次(在變第2頁)。我做錯了什麼,以及如何才能進入第二頁以及之後?

回答

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請求,其中包含一些或所有這些變量的服務器。幸運的是,如果你在頁面2上工作,你可以簡單地增加CurrPage併發送另一個POST來獲得每個後續頁面的結果(不需要提取鏈接)。

更新 - 該網站是一個完全痛苦的屁股,但這裏是一個基於POST的2-N頁面的刮擦。將MAX_PAGE設置爲最高頁碼+1。該腳本將生成像file_000003.html這樣的文件。

注意:在你使用它,你需要與contents of this paste blob更換POSTDATA(其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()) 
+0

感謝您的幫助。我不知道任何Javascript,所以我可以使用機械化提供的一些POST功能,或者我需要在Javascript中做些什麼嗎? – andy 2011-05-02 16:47:50

+0

順便說一句,我曾嘗試以前使用wget和捲曲與這些變量的POST數據,並得到基本相同的行爲:總是隻是得到結果的第一頁,無論我通過什麼CurrPage號碼。這很令人困惑。 – andy 2011-05-02 16:49:20

+0

您可以從機械化提交POST。你試圖抓取的網站正在做一些瘋狂的事情,所以它可能有點涉及到確切需要提交哪些變量。我會用一個機械化POST的例子來更新我的答案,以防萬一。 – samplebias 2011-05-03 20:10:05