在本章中,我们将涵盖以下内容:
-
使用 Scrapy 的网络蜘蛛
-
Scrapy shell
-
将提取器与 Scrapy 链接起来
-
使用 Scrapy 登录网站后进行抓取
Scrapy是最强大的 Python 网络爬虫框架之一,它可以帮助高效地抓取网页的许多基本功能。
网络蜘蛛从要访问的 URL 或 URL 列表开始,当蜘蛛获取新页面时,它会分析页面以识别所有超链接,并将这些链接添加到要爬行的 URL 列表中。只要发现新数据,这个动作就会递归地继续下去。
网络蜘蛛可以找到新的 URL 并对其进行索引以进行爬行,或者从中下载有用的数据。在下面的示例中,我们将使用 Scrapy 创建一个网络蜘蛛。
我们可以从 Python 的pip命令安装 Scrapy:
pip install scrapy 确保您有安装 Scrapy 所需的权限。如果权限出现任何错误,请使用sudo命令。
让我们用 Scrapy 创建一个简单的蜘蛛:
- 要创建一个新的蜘蛛项目,请打开终端并转到我们的蜘蛛所在的文件夹:
$ mkdir new-spider
$ cd new-spider - 然后运行以下命令创建一个带有
scrapy的新蜘蛛项目:
$ scrapy startproject books 这将创建一个名为books的项目,并创建一些有用的文件来创建爬虫。现在你有了一个文件夹结构,如下面的截图所示:
- 现在我们可以使用以下命令创建一个爬虫:
$ scrapy genspider home books.toscrape.com 这将生成名为home的蜘蛛的代码,因为我们计划爬取books.toscrape.com的主页。现在spiders文件夹内的文件夹结构将如下所示:
- 如您所见,
spiders文件夹内有一个名为home.py的文件。我们可以打开home.py并开始编辑它。home.py文件将包含以下代码:
# -*- coding: utf-8 -*-
import scrapy
class HomeSpider(scrapy.Spider):
name = 'home'
allowed_domains = ['books.toscrape.com']
start_urls = ['http://books.toscrape.com/']
def parse(self, response):
pass HomeSpider是scrapy.spider的子类。名称设置为home,这是我们在生成蜘蛛时提供的。allowed_domains属性定义了此爬虫的授权域,start_urls定义了爬虫要开始的 URL。
正如其名称所示,parse方法解析了所访问的 URL 的内容。
- 尝试使用以下命令运行蜘蛛:
$ scrapy crawl home - 现在我们可以重写蜘蛛以浏览分页链接:
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
class HomeSpider(CrawlSpider):
name = 'home'
allowed_domains = ['books.toscrape.com']
start_urls = ['http://books.toscrape.com/']
rules = (Rule(LinkExtractor(allow=(), restrict_css=('.next',)),
callback="parse_page",
follow=True),)
def parse_page(self, response):
print(response.url) 要浏览多个页面,我们可以使用CrawlSpider的子类。从scrapy.spider导入CrawlSpider和Rule模块。对于提取链接,我们可以使用scrapy.linkextractors中的LinkExtractor。
然后我们需要设置rules变量,用于设置通过页面的规则。在这里,我们使用restrict_css参数来设置css类以到达下一页。可以通过在浏览器中检查网页来找到下一页 URL 的css类,如下面的截图所示:
- 通过以下命令运行爬虫来检查爬虫:
$ scrapy crawl home 这将打印出蜘蛛解析的所有 URL。
- 让我们重写脚本以获取书籍的“标题”和“价格”。为此,我们必须为我们的项目创建一个类,因此在
book项目内,我们将创建另一个名为item.py的文件,并定义我们要提取的项目:
from scrapy.item import Item, Field
class BookItem(Item):
title = Field()
price = Field() 在这里,我们定义了一个新类,其中包含我们希望从我们的蜘蛛中提取的细节。现在文件夹结构将如下所示:
- 然后,更新
spider/home.py文件以提取数据:
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from books.item import BookItem
class HomeSpider(CrawlSpider):
name = 'home'
allowed_domains = ['books.toscrape.com']
start_urls = ['http://books.toscrape.com/']
rules = (Rule(LinkExtractor(allow=(), restrict_css=('.next',)),
callback="parse_page",
follow=True),)
def parse_page(self, response):
items = []
books = response.xpath('//ol/li/article')
index = 0
for book in books:
item = BookItem()
title = books.xpath('//h3/a/text()')[index].extract()
item['title'] = str(title).encode('utf-8').strip()
price = books.xpath('//article/div[contains(@class, "product_price")]/p[1]/text()')[index].extract()
item['price'] = str(price).encode('utf-8').strip()
items.append(item)
index += 1
yield item 更新parse_page方法以从每个页面提取“标题”和“价格”详情。要从页面中提取数据,我们必须使用选择器。在这里,我们使用了xpath选择器。XPath 是一种常用的语法或语言,用于浏览 XML 和 HTML 文档。
在parse_page方法中,最初,我们选择了网站上放置书籍详细信息的所有文章标签,并遍历每个文章标签以解析书籍的标题和价格。
- 要获取标签的
xpath选择器,我们可以使用谷歌 Chrome 浏览器的 XPath 工具,如下所示:
我们可以使用 Firefox Inspector 如下:
- 现在我们可以运行爬虫,将数据提取到
.csv文件中:
$ scrapy crawl home -o book-data.csv -t csv 这将在当前目录中创建一个名为book-data.csv的文件,其中包含提取的详细信息。
您可以在doc.scrapy.org/en/latest/topics/selectors.html了解有关选择器(如 XPath)以及如何从页面中选择详细信息的更多信息。
Scrapy shell 是一个命令行界面,可帮助调试脚本而无需运行整个爬虫。我们必须提供一个 URL,Scrapy shell 将打开一个接口,与爬虫在其回调中处理的对象进行交互,例如响应对象。
我们可以通过一些简单的 Scrapy 交互式 shell 用法。步骤如下:
- 打开一个终端窗口,然后输入以下命令:
$ Scrapy shell http://books.toscrape.com/ 加载 Scrapy shell 后,它将打开一个接口,与响应对象进行交互,如下所示:
- 我们可以使用这个接口来调试
response对象的选择器:
>>> response.xpath('//ol/li/article') 这将打印选择器输出。有了这个,我们可以创建和测试爬虫的提取规则。
- 我们还可以从代码中打开 Scrapy shell 以调试提取规则中的错误。为此,我们可以使用
inspect_response方法:
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from scrapy.shell import inspect_response
class HomeSpider(CrawlSpider):
name = 'home'
allowed_domains = ['books.toscrape.com']
start_urls = ['http://books.toscrape.com/']
rules = (Rule(LinkExtractor(allow=(), restrict_css=('.next',)),
callback="parse_page",
follow=True),)
def parse_page(self, response):
if len(response.xpath('//ol/li/article')) < 5:
title = response.xpath('//h3/a/text()')[0].extract()
print(title)
else:
inspect_response(response, self) 如果条件失败,这将打开一个 shell 接口。在这里,我们已经导入了inspect_response并使用它来从代码中调试爬虫。
正如它们的名称所示,链接提取器是用于从 Scrapy 响应对象中提取链接的对象。Scrapy 具有内置的链接提取器,例如scrapy.linkextractors。
让我们用 Scrapy 构建一个简单的链接提取器:
- 与上一个示例一样,我们必须创建另一个 spider 来获取所有链接。
在新的spider文件中,导入所需的模块:
import scrapy
from scrapy.linkextractor import LinkExtractor
from scrapy.spiders import Rule, CrawlSpider - 创建一个新的
spider类并初始化变量:
class HomeSpider2(CrawlSpider):
name = 'home2'
allowed_domains = ['books.toscrape.com']
start_urls = ['http://books.toscrape.com/']- 现在我们必须初始化爬取 URL 的规则:
rules = [
Rule(
LinkExtractor(
canonicalize=True,
unique=True
),
follow=True,
callback="parse_page"
)
] 此规则命令提取所有唯一和规范化的链接,并指示程序跟随这些链接并使用parse_page方法解析它们
- 现在我们可以使用
start_urls变量中列出的 URL 列表启动 spider:
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(url, callback=self.parse, dont_filter=True) start_requests()方法在打开爬虫进行爬取时调用一次
- 现在我们可以编写解析 URL 的方法:
def parse_page(self, response):
links = LinkExtractor(canonicalize=True, unique=True).extract_links(response)
for link in links:
is_allowed = False
for allowed_domain in self.allowed_domains:
if allowed_domain in link.url:
is_allowed = True
if is_allowed:
print link.url 该方法提取相对于当前响应的所有规范化和唯一的链接。它还验证链接的 URL 的域是否属于授权域中的一个。
有时我们必须登录网站才能访问我们计划提取的数据。使用 Scrapy,我们可以轻松处理登录表单和 cookies。我们可以利用 Scrapy 的FormRequest对象;它将处理登录表单并尝试使用提供的凭据登录。
当我们访问一个需要身份验证的网站时,我们需要用户名和密码。在 Scrapy 中,我们需要相同的凭据来登录。因此,我们需要为我们计划抓取的网站获取一个帐户。
以下是我们如何使用 Scrapy 来爬取需要登录的网站:
- 要使用
FormRequest对象,我们可以按如下方式更新parse_page方法:
def parse(self, response):
return scrapy.FormRequest.from_response(
response,
formdata={'username': 'username', 'password': 'password'},
callback=self.parse_after_login
) 在这里,响应对象是我们需要填写登录表单的页面的 HTTP 响应。FormRequest方法包括我们需要登录的凭据以及用于登录后解析页面的callback方法。
- 在保持登录会话的情况下进行分页,我们可以使用前面一篇食谱中使用的方法。






