初始问题
我写一个CrawlSpider类(使用scrapy
库)的方法创建单元测试和依靠大量的scrapy
异步魔法,使其工作。这是,剥离下来:为scrapy CrawlSpider
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()
class属性rule
告诉我蜘蛛遵循一定的联系,并跳转到一个回调函数一旦网络页面下载。我的目标是测试称为parse_page_section
的解析方法,无需运行爬虫,甚至无需发出真正的HTTP请求。
我试过
出于本能,我转身向mock
库。我明白你是如何模拟一个函数来测试它是否已被调用(哪些参数以及是否有任何副作用......),但这不是我想要的。我想实例化一个假对象MySpider
并分配足够的属性以便能够调用parse_page_section
方法。
在上述例子中,我需要一个response
对象来实例化我ItemLoader
和具体为self.response.body
属性来实例我BeautifulSoup
。原则上,我可以做虚假对象是这样的:
from argparse import Namespace
my_spider = MySpider(CrawlSpider)
my_spider.response = NameSpace(body='<html>...</html>')
行之有效,为BeautifulSoup
类,但我需要增加更多的属性创建ItemLoader
对象。对于更复杂的情况,它会变得丑陋难以控制。
我的问题
这是完全正确的方法吗?我在网上找不到类似的例子,所以我认为我的方法在更基础的层面上可能是错误的。任何有识之士将不胜感激。
@ChrisP感谢您的编辑。我并没有把scrapy标签放在首位,因为我认为这个问题一般与单元测试有关。 – cyberbikepunk
这绝对是单元测试,但是大量进行刮擦的人可能会对单元测试刮板有一些独特的见解。 – ChrisP
在这个特殊的'CrawlSpider'的情况下,我可以摆脱伪造响应对象。手工操作很困难,但这有帮助吗? http://requests-mock.readthedocs.io/en/latest/overview.html。这会是一个好方法吗? – cyberbikepunk