2016-04-28 20 views
4

scrapy CrawlSpiderの方法のためのユニットテストを作成し

私は(scrapyライブラリを使用して)CrawlSpiderクラスを書いていますし、それを動作させるためにscrapy非同期魔法の多くに依存しています。ここでは、ストリップダウンされています最初の問題

class MySpider(CrawlSpider): 
    rules = [Rule(LinkExtractor(allow='myregex'), callback='parse_page')] 
    # some other class attributes 

    def __init__(self, *args, **kwargs): 
     super(MySpider, self).__init__(*args, **kwargs) 
     self.response = None 
     self.loader = None 

    def parse_page_section(self): 
     soup = BeautifulSoup(self.response.body, 'lxml') 
     # Complicated scraping logic using BeautifulSoup 
     self.loader.add_value(mykey, myvalue) 

    # more methods parsing other sections of the page 
    # also using self.response and self.loader 

    def parse_page(self, response): 
     self.response = response 
     self.loader = ItemLoader(item=Item(), response=response) 
     self.parse_page_section() 
     # call other methods to collect more stuff 
     self.loader.load_item() 

クラス属性ruleは、特定のリンクをたどると、ウェブページがダウンロードされたら、コールバック関数にジャンプする私のクモを伝えます。私の目標は、クローラを実行せずに実際のHTTPリクエストを作成することなくparse_page_sectionという構文解析メソッドをテストすることです。私は本能的に

を試してみました何

は、私がmockライブラリに自分自身を回しました。私はあなたが関数を模倣して、それが呼び出されたかどうか(引数と副作用があるかどうか)をテストする方法を理解していますが、それは私が望むものではありません。私は擬似オブジェクトMySpiderをインスタンス化し、その上にparse_page_sectionメソッドを呼び出せるだけの属性を割り当てたいと思います。上記の例では

、私は私のBeautifulSoupをインスタンス化するために私ItemLoader、具体的にself.response.body属性をインスタンス化するresponseオブジェクトが必要です。

from argparse import Namespace 

my_spider = MySpider(CrawlSpider) 
my_spider.response = NameSpace(body='<html>...</html>') 

BeautifulSoupクラスのために適していますが、私はItemLoaderオブジェクトを作成するために、より多くの属性を追加する必要があります。原則として、私はこのような偽のオブジェクトを作ることができます。より複雑な状況では、醜く扱いにくいものになるでしょう。

私の質問

これは正しいアプローチですか?私はウェブ上で同様の事例を見つけることができないので、私のアプローチはより根本的なレベルで間違っていると思う。どんな洞察力も大変高く評価されます。

+0

@ChrisPあなたの編集に感謝します。私は最初に「スクラピー」ラベルを貼っていませんでした。なぜなら、その質問は、一般的な単体テストに関係していると思っていたからです。 – cyberbikepunk

+0

ユニットテストは一般的には間違いありませんが、スクレイピングが多い人はユニットテストスクレイパーのためのユニークな洞察を持っているかもしれません。 – ChrisP

+0

この「CrawlSpider」のケースでは、レスポンスオブジェクトの偽装を取り除くことができました。手で行うのは難しいですが、これが助けになるのでしょうか? http://requests-mock.readthedocs.io/ja/latest/overview.html。これは良いアプローチですか? – cyberbikepunk

答えて

1

あなたはSpiders Contractsを見ましたか?

これにより、多くのコードを必要とせずにスパイダーの各コールバックをテストすることができます。たとえば:

def parse(self, response): 
    """ This function parses a sample response. Some contracts are mingled 
    with this docstring. 

    @url http://www.amazon.com/s?field-keywords=selfish+gene 
    @returns items 1 16 
    @returns requests 0 0 
    @scrapes Title Author Year Price 
    """ 

は、契約のチェックを実行するためにcheckコマンドを使用します。

これを見ると、さらに大きいものが必要な場合はanswerとなります。

+0

私はそれがウェブサイト自体が変わることができるので、単体テストの代わりに*実生活*(統合)テストに行くのが理にかなっていると思います。本質的に、単体テストが機能していても、スクラップが確実に働くわけではありません。あなたの提案をありがとう。 – cyberbikepunk

+0

ユニットテストにはまだ値がありますが、最低でもコーディングをしながら健全性チェックが行われます。あなたが提供するもう1つの回答(http://stackoverflow.com/questions/6456304/scrapy-unit-testing/12741030#12741030)では、実際に 'scrap'' Request'を使ってレスポンスオブジェクトをより良い方法で偽装する方法を示しています。 'レスポンス'オブジェクト。ヒント。 – cyberbikepunk

関連する問題