2010-11-22 3 views
2

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

Моя первая итерация программы - это один гигантский файл, который берет веб-сайт в качестве аргумента и сбрасывает этот веб-сайт, если он его распознает, и имеет собственный код для него (с помощью гигантского заявления о случаях, чтобы проверить, признает ли он веб-сайт) ,

Очевидно, что это не большой дизайн, поэтому я хотел бы сделать собственные функции scrape в своих собственных файлах/классах и иметь небольшой скрипт, который я могу использовать для вызова их по имени. Например:

scrape.py --site google 

И я хотел бы иметь файловую структуру, аналогичную:

scrape.py 
sites/ 
    google.py 
    yahoo.py 
    ... 
    bing.py 

Я не освоенной ориентации объекта пока нет, но я признаю, что это взывает к ней, и что то, что я ищу, вероятно, является общим шаблоном OO.

Любая помощь в получении этого кода реорганизована правильно?

PS - Я посмотрел на Scrapy, и это не совсем то, что мне нужно по разным причинам.
PPS - Я на самом деле не очищаю поисковые сайты, я соскабливаю веб-сайты судов США.

ответ

4

Вы можете поместить код в классе с __init__ способом, чтобы получить все настроено, метод _download для подключения к сайту и загрузить его, _store метод, чтобы сохранить результаты и метод run, чтобы связать его все вместе, вот так:

class Scraper(object): 
    def __init__(self, parser, page_generator): 
     self._parser = parser 
     self._pages = pages 

    def _download(self, page): 
     # do whatever you're already doing to download it 
     return html 

    def _store(self, data): 
     # Do whatever you're already doing to store the data 

    def run(self): 
     for page in pages: 
      html = self._download(page) 
      data = self._parser.parse(html) 
      self._store(data) 

Этот класс может жить в файле parser.py.

В каждом конкретном файле вашего сайта укажите две вещи.

class Parser(object): 
    def parse(html): 
     # All of your rules go here 

def pages(some, args, if_, you, need, them): # but they should be the same for all files 
    return a_list_of_pages_or_generator 

Затем вы можете настроить свой файл python.py с помощью следующей функции:

def get_scraper(name): 
    mod = __import__(name) 

    parser = mod.Parser() 
    pages = mod.pages() # Pass whatever args you need to figure out the urls 

    return Scraper(parser, pages) 

Вы можете использовать его как

scraper = get_scraper('google') 
scraper.run() 

Действовать таким образом, имеет преимущество, что не требуется вы внесете изменения в класс Scraper. Если вам нужно сделать разные трюки, чтобы заставить серверы разговаривать со своим скребком, вы можете создать класс Downloader в каждом модуле и использовать его точно так же, как класс Parser. Если у вас есть два или более парсера, которые делают то же самое, просто определите их как общий парсер в отдельном модуле и импортируйте их в модуль каждого сайта, который этого требует. Или подкласс, чтобы сделать хитрости. Не зная, как вы загружаете и разбираете сайты, трудно быть более конкретным.

Мое ощущение, что вам, возможно, придется задать несколько вопросов, чтобы все детали были сглажены, но это будет хороший опыт обучения.

+0

В конечном счете, я использовал оба ответа здесь, чтобы создать библиотеку [Juriscraper] (https://bitbucket.org/mlissner/juriscraper/), но заимствован в большей степени от этого. Действительно полезный материал, спасибо! – mlissner

1

Ваша техника для рефакторинга - это то, как я пойду. Вот как, я смотрю на реализацию этой проблемы.

Первый

Я хотел бы создать одну функцию под названием ScrapeHandler во всех файлах внутри каталога сайтов - google.py, yahoo.py и т.д.

def ScrapeHandler(...): 
    ... 

Второй

Я бы создал каталог __init__.py в каталоге со следующим контентом.

scrapers = ["google", "yahoo", ...] 

Третьего

В главном файле scrape.py, я бы загрузить скребок во время выполнения, чтобы выбрать соответствующую логику выскабливания.

from sites import scrapers 
all_scrapers = {} 
...... 
# Load all scrapers 
for scraper_name in scrapers: 
    all_scrapers[scraper_name] = __import__('%s.%s' % (sites.__name__, scraper_name), fromlist=[scraper_name], level=0) 
# get the input on what to scrape via command line etc 
scraper_name = .. 
assert scraper_name not in scrapers 
# call the function based on name 
scrapeHandler = all_scrapers.get(scraper_name, None) 
if scrapeHandler is not None: 
    scrapeHandler(....) 
+0

Для обработчика я закончил перебирать переменную __all__ в модуле, который я сделал, но да, здесь хороший материал. Спасибо! – mlissner