我正在尝试构建一个可以有效地从许多网站上抓取文本信息的蜘蛛。由于我是Python用户,我被提到了Scrapy。但是,为了避免抓取大型网站,我想限制蜘蛛每页不超过20页的某个“深度” 。这是我的蜘蛛:
class DownloadSpider(CrawlSpider):
name = 'downloader'
download_path = '/home/MyProjects/crawler'
rules = (Rule(SgmlLinkExtractor(), callback='parse_item', follow=True),)
def __init__(self, *args, **kwargs):
super(DownloadSpider, self).__init__(*args, **kwargs)
self.urls_file_path = [kwargs.get('urls_file')]
data = open(self.urls_file_path[0], 'r').readlines()
self.allowed_domains = [urlparse(i).hostname.strip() for i in data]
self.start_urls = ['http://' + domain for domain in self.allowed_domains]
def parse_start_url(self, response):
return self.parse_item(response)
def parse_item(self, response):
self.fname = self.download_path + urlparse(response.url).hostname.strip()
open(str(self.fname)+ '.txt', 'a').write(response.url)
open(str(self.fname)+ '.txt', 'a').write('\n')
urls_file是带有网址的文本文件的路径。我还在设置文件中设置了最大深度。这是我的问题:如果我设置了CLOSESPIDER_PAGECOUNT
异常,当总抓取页数(无论哪个站点)达到异常值时,它会关闭蜘蛛。但是,当我从每个网址上说20页时,我需要停止抓取。
我也尝试使用像self.parsed_number + = 1这样的变量保持计数,但这也不起作用 - 似乎scrapy不会通过url进行url但是将它们混合起来。
任何建议都非常感谢!
答案 0 :(得分:2)
我会创建每个类变量,使用stats = defaultdict(int)
初始化它,并在{self.stats[response.url]
中增加(website, depth)
(或者可能是关键字可能是parse_item
中的元组)urlparse.urlparse
1}}。
这就是我想象的 - 应该在理论上运作。如果您需要一个例子,请告诉我。
仅供参考,您可以在{{1}}的帮助下提取基本网址并计算深度(参见docs)。
答案 1 :(得分:2)
为此,您可以基于SgmlLinkExtractor创建自己的链接提取器类。看起来应该是这样的:
from scrapy.selector import Selector
from scrapy.utils.response import get_base_url
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
class LimitedLinkExtractor(SgmlLinkExtractor):
def __init__(self, allow=(), deny=(), allow_domains=(), deny_domains=(), restrict_xpaths=(),
tags=('a', 'area'), attrs=('href'), canonicalize=True, unique=True, process_value=None,
deny_extensions=None, max_pages=20):
self.max_pages=max_pages
SgmlLinkExtractor.__init__(self, allow=allow, deny=deny, allow_domains=allow_domains, deny_domains=deny_domains, restrict_xpaths=restrict_xpaths,
tags=tags, attrs=attrs, canonicalize=canonicalize, unique=unique, process_value=process_value,
deny_extensions=deny_extensions)
def extract_links(self, response):
base_url = None
if self.restrict_xpaths:
sel = Selector(response)
base_url = get_base_url(response)
body = u''.join(f
for x in self.restrict_xpaths
for f in sel.xpath(x).extract()
).encode(response.encoding, errors='xmlcharrefreplace')
else:
body = response.body
links = self._extract_links(body, response.url, response.encoding, base_url)
links = self._process_links(links)
links = links[0:self.max_pages]
return links
此子类的代码完全基于类SgmlLinkExtractor的代码。我刚刚将变量 self.max_pages 添加到类构造函数和行中,该行剪切了 extract_links 方法末尾的链接列表。但是你可以更聪明地削减这个列表。