我编写了以下代码来抓取电子邮件地址(用于测试目的):
import scrapy
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors import LinkExtractor
from scrapy.selector import Selector
from crawler.items import EmailItem
class LinkExtractorSpider(CrawlSpider):
name = 'emailextractor'
start_urls = ['http://news.google.com']
rules = ( Rule (LinkExtractor(), callback='process_item', follow=True),)
def process_item(self, response):
refer = response.url
items = list()
for email in Selector(response).re("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}"):
emailitem = EmailItem()
emailitem['email'] = email
emailitem['refer'] = refer
items.append(emailitem)
return items
不幸的是,似乎对Requests的引用没有正确关闭,与scrapy telnet控制台一样,Requests的数量增加了5k/s。在大约 3 分钟和 10k 刮擦页面后,我的系统开始交换(8GB RAM)。
有人知道出了什么问题吗?
我已经尝试删除引用并使用“复制”字符串
emailitem['email'] = ''.join(email)
没有成功。
抓取后,这些项目将保存到 BerkeleyDB 中,计算它们的出现次数(使用管道),因此引用应该在之后消失。
返回一组项目和单独生成每个项目有什么区别?
EDIT:
经过相当长一段时间的调试后,我发现请求没有被释放,因此我最终得到:
$> nc localhost 6023
>>> prefs()
Live References
Request 10344 oldest: 536s ago
>>> from scrapy.utils.trackref import get_oldest
>>> r = get_oldest('Request')
>>> r.url
<GET http://news.google.com>
这实际上是起始网址。
有人知道问题是什么吗?缺少对 Request 对象的引用在哪里?
EDIT2:
在服务器(具有 64GB RAM)上运行约 12 小时后,使用的 RAM 约为 16GB(使用 ps,即使 ps 不是合适的工具)。问题是,抓取的页面数量显着下降,而抓取的项目数量自数小时以来一直保持为 0:
INFO: Crawled 122902 pages (at 82 pages/min), scraped 3354 items (at 0 items/min)
EDIT3:
I did the objgraph analysis which results in the following graph (thanks @Artur Gaspar):
我似乎无法影响它?