常见问题¶
Scrapy 与 BeautifulSoup 或 lxml 相比如何?¶
BeautifulSoup 和 lxml 是用于解析HTML和XML的库。Scrapy 是一个用于编写网络爬虫的应用程序框架,这些爬虫可以爬取网站并从中提取数据。
Scrapy 提供了一个内置的数据提取机制(称为 selectors),但如果你觉得更习惯使用 BeautifulSoup (或 lxml),你也可以轻松地使用它们。毕竟,它们只是可以从任何 Python 代码中导入和使用的解析库。
换句话说,将BeautifulSoup(或lxml)与Scrapy进行比较,就像将jinja2与Django进行比较一样。
我可以将Scrapy与BeautifulSoup一起使用吗?¶
是的,你可以。
正如上面提到的,BeautifulSoup 可以用于
在Scrapy回调中解析HTML响应。
你只需要将响应的主体输入到 BeautifulSoup 对象中
并从中提取你需要的任何数据。
这是一个使用BeautifulSoup API的示例爬虫,使用lxml作为HTML解析器:
from bs4 import BeautifulSoup
import scrapy
class ExampleSpider(scrapy.Spider):
name = "example"
allowed_domains = ["example.com"]
start_urls = ("http://www.example.com/",)
def parse(self, response):
# use lxml to get decent HTML parsing speed
soup = BeautifulSoup(response.text, "lxml")
yield {"url": response.url, "title": soup.h1.string}
注意
BeautifulSoup 支持多种HTML/XML解析器。
请参阅 BeautifulSoup的官方文档 了解哪些解析器可用。
Scrapy 是否从 Django “偷” 了 X?¶
可能吧,但我们不喜欢那个词。我们认为Django是一个很棒的开源项目,也是一个值得学习的榜样,所以我们用它作为Scrapy的灵感来源。
我们相信,如果某件事已经做得很好了,就没有必要重新发明轮子。这一概念不仅是开源和自由软件的基础之一,不仅适用于软件,也适用于文档、程序、政策等。因此,与其自己解决每个问题,我们选择从那些已经妥善解决问题的项目中复制想法,并专注于我们需要解决的实际问题。
如果Scrapy能成为其他项目的灵感来源,我们将感到非常自豪。欢迎随意借鉴我们的成果!
Scrapy 是否支持 HTTP 代理?¶
是的。自Scrapy 0.8版本起,通过HTTP代理下载器中间件提供了对HTTP代理的支持。请参阅
HttpProxyMiddleware。
如何在不同页面中抓取具有属性的项目?¶
参见 向回调函数传递额外数据。
如何在我的爬虫中模拟用户登录?¶
Scrapy是按广度优先还是深度优先顺序爬取?¶
默认情况下,Scrapy使用LIFO队列来存储待处理的请求,这基本上意味着它以DFO顺序进行爬取。在大多数情况下,这种顺序更为方便。
如果你确实想以真正的BFO顺序进行爬取,你可以通过设置以下设置来实现:
DEPTH_PRIORITY = 1
SCHEDULER_DISK_QUEUE = "scrapy.squeues.PickleFifoDiskQueue"
SCHEDULER_MEMORY_QUEUE = "scrapy.squeues.FifoMemoryQueue"
当待处理的请求低于配置的值时,CONCURRENT_REQUESTS、CONCURRENT_REQUESTS_PER_DOMAIN 或 CONCURRENT_REQUESTS_PER_IP,这些请求会并发发送。因此,爬虫的前几个请求很少遵循所需的顺序。将这些设置降低到 1 可以强制执行所需的顺序,但会显著减慢整个爬取过程。
我的Scrapy爬虫有内存泄漏问题。我该怎么办?¶
参见 调试内存泄漏。
此外,Python 有一个内置的内存泄漏问题,这在 Leaks without leaks 中有描述。
如何让Scrapy消耗更少的内存?¶
参见上一个问题。
如何防止由于允许的域名过多而导致的内存错误?¶
如果你有一个包含大量allowed_domains的爬虫(例如超过50,000个),考虑用内存需求较少的自定义下载器中间件替换默认的OffsiteMiddleware下载器中间件。例如:
如果你的域名足够相似,使用你自己的正则表达式,而不是将字符串加入到
allowed_domains中形成一个复杂的正则表达式。如果您能满足安装要求,请使用 pyre2 而不是 Python 的 re 来编译您的 URL 过滤正则表达式。请参阅 issue 1908。
另请参阅StackOverflow上的其他建议。
注意
请记住,在启用自定义实现时,禁用
scrapy.downloadermiddlewares.offsite.OffsiteMiddleware:
DOWNLOADER_MIDDLEWARES = {
"scrapy.downloadermiddlewares.offsite.OffsiteMiddleware": None,
"myproject.middlewares.CustomOffsiteMiddleware": 50,
}
我可以在我的爬虫中使用基本HTTP认证吗?¶
是的,请参见 HttpAuthMiddleware。
为什么Scrapy下载的页面是英文而不是我的母语?¶
尝试通过覆盖DEFAULT_REQUEST_HEADERS设置来更改默认的Accept-Language请求头。
我在哪里可以找到一些Scrapy项目的示例?¶
参见 示例。
我可以在不创建项目的情况下运行爬虫吗?¶
是的。你可以使用runspider命令。例如,如果你有一个写在my_spider.py文件中的爬虫,你可以这样运行它:
scrapy runspider my_spider.py
查看 runspider 命令以获取更多信息。
我收到“过滤的站外请求”消息。如何修复它们?¶
这些消息(使用DEBUG级别记录)不一定意味着存在问题,因此您可能不需要修复它们。
这些消息是由
OffsiteMiddleware 抛出的,这是一个
下载器中间件(默认启用),其目的是过滤掉
对蜘蛛覆盖范围之外的域的请求。
在生产环境中部署Scrapy爬虫的推荐方式是什么?¶
参见 部署爬虫。
我可以使用JSON进行大规模导出吗?¶
这将取决于您的输出有多大。请参阅此警告在JsonItemExporter文档中。
我可以从信号处理程序中返回(Twisted)延迟对象吗?¶
一些信号支持从其处理程序返回延迟,而另一些则不支持。请参阅内置信号参考以了解哪些信号支持。
响应状态码999是什么意思?¶
999 是雅虎网站用于限制请求的自定义响应状态码。
尝试通过在您的爬虫中使用 2(或更高)的下载延迟来减慢爬取速度:
from scrapy.spiders import CrawlSpider
class MySpider(CrawlSpider):
name = "myspider"
download_delay = 2
# [ ... rest of the spider code ... ]
或者通过在您的项目中设置全局下载延迟,使用
DOWNLOAD_DELAY 设置。
我可以从我的爬虫中调用pdb.set_trace()来调试它们吗?¶
是的,但你也可以使用Scrapy shell,它允许你快速分析(甚至修改)你的爬虫正在处理的响应,这通常比普通的pdb.set_trace()更有用。
更多信息请参见从爬虫调用shell以检查响应。
将我的所有抓取项转储到JSON/CSV/XML文件的最简单方法?¶
转储到JSON文件:
scrapy crawl myspider -O items.json
转储到CSV文件:
scrapy crawl myspider -O items.csv
转储到XML文件:
scrapy crawl myspider -O items.xml
更多信息请参见 Feed exports
这个巨大的神秘__VIEWSTATE参数在某些表单中是用来做什么的?¶
__VIEWSTATE 参数用于使用 ASP.NET/VB.NET 构建的网站。有关其工作原理的更多信息,请参阅 此页面。此外,这里有一个 示例爬虫,它抓取了其中一个网站。
解析大型XML/CSV数据源的最佳方法是什么?¶
使用XPath选择器解析大型feed可能会出现问题,因为它们需要在内存中构建整个feed的DOM,这可能会非常慢并且消耗大量内存。
为了避免一次性在内存中解析整个feed,你可以使用
xmliter_lxml() 和
csviter() 函数。实际上,这就是
XMLFeedSpider 所使用的。
- scrapy.utils.iterators.xmliter_lxml(obj: Response | str | bytes, nodename: str, namespace: str | None = None, prefix: str = 'x') Iterator[Selector][source]¶
- scrapy.utils.iterators.csviter(obj: Response | str | bytes, delimiter: str | None = None, headers: list[str] | None = None, encoding: str | None = None, quotechar: str | None = None) Iterator[dict[str, str]][源代码]¶
从给定的csv对象返回字典的迭代器
obj 可以是: - 一个 Response 对象 - 一个 unicode 字符串 - 一个以 utf-8 编码的字符串
delimiter 是用于在给定对象上分隔字段的字符。
headers 是一个可迭代对象,当提供时,它为返回的字典提供键,如果没有提供,则使用第一行。
quotechar 是用于在给定对象上封闭字段的字符。
如何指示蜘蛛停止自身?¶
从回调中引发 CloseSpider 异常。更多信息请参见:CloseSpider。
如何防止我的Scrapy机器人被封禁?¶
参见 避免被封禁。
我应该使用爬虫参数还是设置来配置我的爬虫?¶
无论是spider arguments还是settings都可以用来配置你的爬虫。没有严格的规则规定必须使用哪一种,但设置更适合那些一旦设置后就不太会改变的参数,而爬虫参数则意味着更频繁的更改,甚至在每次爬虫运行时都可能需要更改,有时是爬虫运行所必需的(例如,设置爬虫的起始URL)。
为了举例说明,假设你有一个需要登录网站以抓取数据的爬虫,而你只想从网站的某个部分(每次都会变化)抓取数据。在这种情况下,登录的凭据将是设置,而要抓取的部分的URL将是爬虫的参数。
我正在抓取一个XML文档,但我的XPath选择器没有返回任何项目¶
您可能需要移除命名空间。请参阅移除命名空间。
如何在项目管道中将一个项目拆分为多个项目?¶
Item pipelines 不能为每个输入项生成多个项。请改用 创建一个蜘蛛中间件,并使用其 process_spider_output() 方法来实现此目的。例如:
from copy import deepcopy
from itemadapter import is_item, ItemAdapter
class MultiplyItemsMiddleware:
def process_spider_output(self, response, result, spider):
for item in result:
if is_item(item):
adapter = ItemAdapter(item)
for _ in range(adapter["multiply_by"]):
yield deepcopy(item)
Scrapy 是否支持 IPv6 地址?¶
是的,通过将DNS_RESOLVER设置为scrapy.resolver.CachingHostnameResolver。
请注意,这样做会失去为DNS请求设置特定超时的能力
(DNS_TIMEOUT设置的值将被忽略)。
如何处理 'ValueError'>: filedescriptor out of range in select() 异常?¶
此问题已被报告在macOS上运行广泛爬取时出现,其中默认的Twisted反应器是twisted.internet.selectreactor.SelectReactor。通过使用TWISTED_REACTOR设置,可以切换到不同的反应器。
如何取消给定响应的下载?¶
在某些情况下,停止下载某个响应可能很有用。
例如,有时您可以通过检查响应的头部或主体的前几个字节来确定是否需要响应的全部内容。在这种情况下,您可以通过将处理程序附加到bytes_received
或headers_received信号并引发
StopDownload异常来节省资源。请参阅
停止下载响应主题以获取更多信息和示例。
如何发出空白请求?¶
from scrapy import Request
blank_request = Request("data:,")
在这种情况下,URL被设置为数据URI方案。数据URL允许您在网页中内联包含数据,类似于外部资源。带有空内容(“,”)的“data:”方案本质上创建了一个对没有任何特定内容的数据URL的请求。
运行 runspider 时出现 error: No spider found in file: ¶
如果您的Scrapy项目有一个与Python标准库模块名称冲突的爬虫模块,例如csv.py或os.py,或者您安装的任何Python包,可能会发生这种情况。请参阅问题2680。