Открытие нескольких страниц с помощью Mechanize в Python - PullRequest
1 голос
/ 05 декабря 2011

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

http://hansard.millbanksystems.com/offices/prime-minister

, и я хочу перейти по каждой ссылке на странице в таком формате, как

<li class='office-holder'><a href="http://hansard.millbanksystems.com/people/mr-tony-blair">Mr Tony Blair</a> May  2, 1997 - June 27, 2007</li>

Другими словами, я хочу перейти по каждой ссылке, которая имеет класс «office-holder» или имеет / people / в URL.Я попробовал следующий код, но он не сработал.

import mechanize

br = mechanize.Browser()
response = br.open("http://hansard.millbanksystems.com/offices/prime-minister")
links = br.links(url_regex="/people/")

print links

Я пытаюсь напечатать ссылки, чтобы убедиться, что я получаю правильные ссылки / информацию, прежде чем писать какие-либобольше кодаОшибка (?) Я получаю от этого:

<generator object _filter_links at 0x10121e6e0>

Любые указатели или советы приветствуются.

1 Ответ

2 голосов
/ 05 декабря 2011

Это не ошибка - это означает, что Browser.links() возвращает объект-генератор, а не список.

Итератор - это объект, который действует как список, то естьВы можете делать такие вещи, как

for link in links:
    print link

и так далее.Но вы можете получить доступ к вещам только в том порядке, в котором они определены;вы не можете делать link[5], и как только вы пройдете через итератор, он израсходован.

Генератор для большинства целей - просто итератор, который не обязательно знает все свои результаты.заблаговременно.Это очень полезно в выражениях генератора , и вы можете написать очень простые функции, которые возвращают генераторы с ключевым словом yield:

def odds():
    x = 1
    while True:
        yield x
        x += 2

 os = odds()
 os.next() # returns 1
 os.next() # returns 3

Это хорошо, потому что это означает, что вы неВам не нужно хранить все ваши данные в памяти одновременно (что для odds() было бы невозможно ...), и если вам нужны только первые несколько элементов результата, вам не нужно беспокоиться об остальном.Модуль itertools имеет несколько удобных функций для работы с итераторами.

В любом случае, если вы просто хотите распечатать содержимое links, вы можете превратить его в список с помощью функции list() (которая принимает итерацию и возвращает список ее элементов):

 print list(links)

или составьте список строк с пониманием списка:

 print [l.url for l in list(links)]

или пройдитесь по его элементам и распечатайте их:

 for l in links:
      print l.url

Но обратите внимание, что после того, как вы выполнитеэто, links будет «исчерпано» - поэтому, если вы действительно хотите что-то с ним сделать, вам нужно получить его снова.

Возможно, самый простой вариант - немедленно превратить его в список ине беспокойтесь о том, что он итератор вообще:

links = list(br.links(url_regex="/people/"))

Кроме того, вы, очевидно, еще не получаете ссылки с нужным вам классом.Здесь может быть какой-то mechanize трюк, чтобы сделать «или», но отличный способ сделать это с помощью наборов и выражений генератора будет выглядеть примерно так:

 links = set(l.url for l in br.links(url_regex='/people/'))
 links.update(l.url for l in br.get_links_with_class('office-holder'))

Очевидно, замените get_links_with_class нареальный способ получить эти ссылки.Затем вы получите набор всех URL-адресов ссылок, которые имеют /people/ в своем URL-адресе и / или имеют класс office-holder, без дубликатов.(Обратите внимание, что вы не можете поместить объекты Link в набор напрямую, потому что они не могут быть хэшируемыми.)

...