2010-11-22 12 views
2

私はウェブサイトを掻き集めるためのPythonコードをいくつか書いていますが、最終的にはカスタムスクレイパーコレクションが増えています特定のウェブサイトから特定の情報を抽出します。お互いに大きく異なるが、同様に処理される機能のパターンとデザイン

私の最初の反復は、ウェブサイトを引数とする巨大なファイルの1つです。それを認識してカスタムコードを持っている場合は、そのWebサイトをスクラップします(巨大ケースのステートメントを使用して、 。

明らかに、これは素晴らしいデザインではないので、カスタムスクレープ関数を独自のファイル/クラスにプルし、小さなスクリプトを使用して名前で呼び出すことができます。

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ファイルに存在します。

サイト固有のファイルのそれぞれに、2つのものを入れます。

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クラスのように使用することができます。同じことをするパーサーが2つ以上ある場合は、別々のモジュールの汎用パーサーとして定義し、必要な各サイトのモジュールにインポートします。または、サブクラス化して調整を行います。どのようにサイトをダウンロードして解析しているかわからなければ、より具体的にするのは難しいです。

私の感覚は、すべての細部を細かくするためにいくつかの質問をしなければならないかもしれないということですが、それは良い学習体験になります。

+0

最終的に、私は[Juriscraper](https://bitbucket.org/mlissner/juriscraper/)ライブラリを構築するために、ここへの両方の答えを使用しましたが、これをもっと重く借用しました。本当に役立つもの、ありがとう! – mlissner

1

あなたのリファクタリングのテクニックは、私がどのように行っていくかです。ここでは、私はこの問題を実装する方法を見ています。

まず

私はサイトディレクトリ内のすべてのファイルにScrapeHandlerと呼ばれる単一の関数を作成します

- google.py、yahoo.pyなど

def ScrapeHandler(...): 
    ... 

セカンド

私は以下の内容のサイトディレクトリに__init__.pyを作成します。メインファイルscrape.pyで

サード

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

、私は適切なスクレイピングロジックを選択し、実行時にスクレーパーをロードします。

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

関連する問題