Проблемы с механизацией follow_link () и back () - PullRequest
4 голосов
/ 02 ноября 2009

Я столкнулся с проблемой механизации следующих ссылок. Вот фрагмент того, что я собираюсь сделать:

for link in mech.links(url_regex='/test/'):
    mech.follow_link(link)

    // Do some processing on that link

    mech.back()

В соответствии с примерами механизации, это должно работать просто отлично. Однако это не так. Несмотря на вызов .back (), цикл заканчивается, хотя есть еще ссылки для посещения. Если я закомментирую mech.follow_link (link) и mech.back (), заменив их на print link.text, он распечатает все 50 или около того ссылок. Однако ... как только я раскомментирую mech.follow_link, цикл сразу же завершается после первой follow_link. back () работает, в том случае, если я печатаю mech.title (), затем вызываю mech.back () и снова печатаю mech.title (), он четко показывает первый заголовок, а затем заголовок страницы «назад» Я действительно запутался, и вот как это делается в документах. Не уверен, что происходит.

Ответы [ 3 ]

2 голосов
/ 07 ноября 2009

Пират, я согласен, этого не должно происходить, вы делаете в точности то, что написано на странице документации по адресу wwwsearch.sourceforge.net/mechanize/; Я попробовал код, похожий на ваш, и получил тот же результат, где он остановился после первой итерации.

Однако я нашел обходной путь, а именно, чтобы сохранить URL-адреса ссылок из links () в списке, а затем следовать каждому URL-адресу из этого списка:

from mechanize import Browser
br = Browser()
linklist = []
br.open(your_page_here)
for link in br.links(url_regex='/test/'): linklist.append(link.url)
for url in linklist:
    br.open(url)
    print br.title()

Это уродливо, и вам не нужно это делать, но, похоже, это сработает.

Я не очень доволен механизацией для подобных ошибок (и проблема, с которой я столкнулся при механизации, плохо обрабатывающей две кнопки отправки ), но она очень проста в установке, кажется довольно переносимой и может работать в автономном режиме (с помощью простых заданий cron) легко сравнивать с другими средами тестирования, такими как Selenium (seleniumhq dot org), который выглядит великолепно, но, кажется, намного больше требует для фактической настройки и использования.

1 голос
/ 15 сентября 2012

Гораздо более простой обходной путь, чем сохранение списка ссылок, - просто получить второй объект Browser. Это можно считать эквивалентным открытию второй вкладки в «реальном» браузере. Если вам также нужна аутентификация, вам нужно будет предоставить файл cookie между экземплярами браузера:

import mechanize
import cookielib

br = mechanize.Browser()
br2 = mechanize.Browser()
cj = cookielib.LWPCookieJar()
br.set_cookiejar(cj)
br2.set_cookiejar(cj)

br.open("http://yoursite.com/login")
br.select_form(nr=0)
br["username"] = "..."   # The hash keys are the names of the form fields
br["password"] = "..."
br.submit()    # This will save the authentication cookie to the shared cookie jar!
br.open("http://yoursite.com/page-to-parse")

for link in br.links(url_regex="/link_text"):
    req = br.click_link(url=link.url)
    html = br2.open(req).read()

Обратите внимание, что необходимо получить объект запроса из первого экземпляра, а затем отправить его со вторым. Это эквивалентно команде «Открыть в новом окне / вкладке» в «реальном» браузере.

0 голосов
/ 27 января 2015

при каждом посещении страницы итератор links () сбрасывает ссылки на этой новой странице. поэтому вам нужно сохранить его в отдельную переменную, например: links = mech.links(), или, как указал Chirael, links = list(mech.links()), что дает преимущество в том, что его можно считать с помощью print >>sys.stderr, '# links: %d' % len(links). это не ошибка в mechanize.Browser, это просто побочный эффект наличия объекта с состоянием.

Еще одна проблема, с которой я столкнулся во время игры, заключается в том, что вы не можете использовать mech.back(), если mech.request не было задано с самого начала, а не было бы, если бы mech.set_response() использовалось для установки исходного содержимого страницы. в этом случае вы должны явно установить первый запрос на что-то: mech.request = mechanize.Request('about://config'). в противном случае вы получите BrowserStateError: already at start of history.

и ради полноты, если кто-то приходит сюда из поиска Google, как я, убедитесь, что заголовки установлены в mechanize.make_response, чтобы, как минимум, (('content-type', 'text/html'),) или mech.viewing_html остались False и mech.links() повысит BrowserStateError("not viewing HTML").

...