使用一个Scrapy爬虫抓取多个网站

12 投票
4 回答
7742 浏览
提问于 2025-04-15 20:07

我需要创建一个用户可以自定义的网络爬虫,我在考虑使用Scrapy这个工具。但是,我不能把域名和允许的URL规则写死在代码里——这些应该可以在一个图形界面中进行设置。

我该如何(尽量简单)用Scrapy创建一个爬虫,或者一组爬虫,让域名和允许的URL规则可以动态配置呢?比如,我把配置写到一个文件里,然后爬虫可以以某种方式读取这个文件。

4 个回答

3

在这里我来宣传一下我的项目 domo!在你的项目中,你需要按照示例中的方法来创建一个爬虫。

另外,你还需要让这个爬虫在运行时可以配置,也就是说,当配置发生变化时,只需要把新的设置传给爬虫,就能覆盖原来的设置。

4

你需要做的是动态创建爬虫类,也就是从你喜欢的通用爬虫类(比如scrapy提供的CrawlSpider,可以加上你的rules,或者XmlFeedSpider,等等)进行继承,然后添加domain_namestart_urls,还有可能的extra_domain_names(和/或start_requests()等),这些信息可以从你的图形界面(GUI)、配置文件或其他地方获取或推断出来。

Python让动态创建类对象变得很简单;一个非常简单的例子可能是:

from scrapy import spider

def makespider(domain_name, start_urls,
               basecls=spider.BaseSpider):
  return type(domain_name + 'Spider',
              (basecls,),
              {'domain_name': domain_name,
               'start_urls': start_urls})

allspiders = []
for domain, urls in listofdomainurlpairs:
  allspiders.append(makespider(domain, urls))

这会给你一系列非常基础的爬虫类——在你实例化它们之前,可能还需要给它们添加parse方法。根据需要调整一下就好...;-)

10

警告:这个答案是针对Scrapy v0.7的,之后蜘蛛管理器的API变化很大。

你可以覆盖默认的SpiderManager类,从数据库或其他地方加载你自己的规则,然后用你自己的规则、正则表达式和域名实例化一个自定义的蜘蛛。

在mybot/settings.py中:

SPIDER_MANAGER_CLASS = 'mybot.spidermanager.MySpiderManager'

在mybot/spidermanager.py中:

from mybot.spider import MyParametrizedSpider

class MySpiderManager(object):
    loaded = True

    def fromdomain(self, name):
        start_urls, extra_domain_names, regexes = self._get_spider_info(name)
        return MyParametrizedSpider(name, start_urls, extra_domain_names, regexes)

    def close_spider(self, spider):
        # Put here code you want to run before spiders is closed
        pass

    def _get_spider_info(self, name):
        # query your backend (maybe a sqldb) using `name` as primary key, 
        # and return start_urls, extra_domains and regexes
        ...
        return (start_urls, extra_domains, regexes)

然后在mybot/spider.py中创建你的自定义蜘蛛类:

from scrapy.spider import BaseSpider

class MyParametrizedSpider(BaseSpider):

    def __init__(self, name, start_urls, extra_domain_names, regexes):
        self.domain_name = name
        self.start_urls = start_urls
        self.extra_domain_names = extra_domain_names
        self.regexes = regexes

     def parse(self, response):
         ...

注意事项:

  • 如果你想利用CrawlSpider的规则系统,也可以扩展它。
  • 要运行一个蜘蛛,可以使用:./scrapy-ctl.py crawl <name>,其中name会传递给SpiderManager.fromdomain,并且是从后端系统获取更多蜘蛛信息的关键。
  • 由于解决方案覆盖了默认的SpiderManager,经典的蜘蛛(每个蜘蛛一个Python模块)将无法工作,但我认为这对你来说不是问题。关于默认蜘蛛管理器的更多信息可以查看TwistedPluginSpiderManager

撰写回答