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
オブジェクトを作成するために、より多くの属性を追加する必要があります。原則として、私はこのような偽のオブジェクトを作ることができます。より複雑な状況では、醜く扱いにくいものになるでしょう。
私の質問
これは正しいアプローチですか?私はウェブ上で同様の事例を見つけることができないので、私のアプローチはより根本的なレベルで間違っていると思う。どんな洞察力も大変高く評価されます。
@ChrisPあなたの編集に感謝します。私は最初に「スクラピー」ラベルを貼っていませんでした。なぜなら、その質問は、一般的な単体テストに関係していると思っていたからです。 – cyberbikepunk
ユニットテストは一般的には間違いありませんが、スクレイピングが多い人はユニットテストスクレイパーのためのユニークな洞察を持っているかもしれません。 – ChrisP
この「CrawlSpider」のケースでは、レスポンスオブジェクトの偽装を取り除くことができました。手で行うのは難しいですが、これが助けになるのでしょうか? http://requests-mock.readthedocs.io/ja/latest/overview.html。これは良いアプローチですか? – cyberbikepunk