为了帮助大家建立对 Scrapy 框架的初步印象,我们使用它完成一个简单的爬虫项目。
01 项目需求
在专门供爬虫初学者训练爬虫技术的网站(http://books.toscrape.com)上爬取书籍信息,如下图所示:
该网站中,这样的书籍列表页面一共有 50 页,每页有 20 本书,第一个例子应该尽量简单。我们下面仅爬取所有图书(1000本)的书名和价格信息。
02 创建项目
首先,我们要创建一个 Scrapy 项目,在 shell 中使用如下命令创建:
scrapy startproject 项目名
如:
scrapy startproject demo1
创建好一个名为 demo1 的项目后,可使用 tree 命令查看项目目录下的文件。
命令如下:
tree demo1
显示如下:
随着后面的深入学习,大家会了解这些文件的用途,此处不做解释。
扩展备注:
如果使用的是 mac os 系统,可能默认不支持 tree 命令,可使用如下命令安装:
brew install tree
如果连brew也没有安装的话,可以使用如下命令安装brew,按照提示操作即可:
/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"
03 分析页面
编写爬虫之前,首先需要对待爬取的页面进行分析,主流的浏览器中都带有分析页面的工具或插件,这里我们选用 Chrome 浏览器(谷歌浏览器)的开发者工具(Tools - Developer tools)分析页面。
1、数据信息
在 Chrome 浏览器中打开页面 http://books.toscrape.com/ ,选中其中任意一本书并右击,然后选择 “检查”(有的浏览器或谷歌浏览器其他版本也叫“审查元素”),查看其 HTML 代码,如下图所示:
可以看到,每一本书的信息包裹在 元素中,书名信息在其下 h3 > a 元素的 title 属性中,
A Light in the ...
如下图:
书价信息在其下
元素的文本中,
£51.77
如下图:
2、链接信息
上图所示,为第一页书籍列表页面,可以通过单击 next 按钮访问下一页访问下方的 next 按钮并右击,然后选择“检查”,查看其 HTML 代码,如下图:
可以发现,下一页的 URL 在 ul.pager > li.next > a 元素的 href 属性中,是一个相对 URL 地址,如:
next
3、实现Spider
分析完页面后,接下来编写爬虫。在 Scrapy 中编写一个爬虫,即实现一个 scrapy.Spider 的子类。
实现爬虫的 Python 文件应位于 demo1/spiders 目录中,在该目录下创建新文件 book_spider.py。
然后,在 book_spider.py 中实现爬虫 BooksSpider,代码如下:
# -*- coding: utf-8 -*-# 欢迎关注微信公众号“码上”,了解更多教程信息# website: https://www.05dt.com/# github: https://github.com/05dt/scrapy# -*- coding: utf-8 -*-import scrapyclass BooksSpider(scrapy.Spider): # 每一个爬虫的唯一标识 name = "books" # 定义爬虫爬取的起始点,起始点可以是多个,这里只有一个 start_urls = ['http://books.toscrape.com/'] def parse(self, response): # 提取数据 # 每一本书的信息在 元素中,我们使用css()方法找到所有这样的article元素,并依次迭代 for book in response.css('article.product_pod'): # 书名信息在 article > h3 > a 元素的title属性里 name = book.xpath('./h3/a/@title').extract_first() # 书的价格信息在
£23.88
的TEXT中 price = book.css('p.price_color::text').extract_first() yield{ '书名': name, '价格': price, } # 提取翻页链接 # 下一页next按钮的url 在 ul.pager > li.next > a 元素的 href 属性中 next_url = response.css('ul.pager li.next a::attr(href)').extract_first() if next_url: # 如果找到下一页的url,得到绝对路径,构造新的Request对象 # 使用urljoin()方法构建完整的绝对URL next_url = response.urljoin(next_url) yield scrapy.Request(next_url, callback=self.parse)
如果上述代码中有看不懂的部分,大家不必担心,更多详细内容会在后面章节学习,这里只要先对实现一个爬虫有个整体印象即可。
下面对 BooksSpider 的实现做简单说明。
- name 属性一个 Scrapy 项目中可能有多个爬虫,每个爬虫的 name 属性是其自身的唯一标识,在一个项目中不能有同名的爬虫,本例中的爬虫取名为“books”。
- start_urls 属性一个爬虫总要从某个(或某些)页面开始爬取,我们称这样的页面为起始爬取点,start_urls 属性用来设置一个爬虫的起始爬取点。本例中只要一个起始爬取点“http://books.toscrape.com/”。
- parse 方法当一个页面下载完成后,Scrapy 引擎会回调一个我们指定的页面解析函数(默认为 parse 方法)解析页面。一个页面解析函数通常需要完成以下两个任务:①提取页面中的数据(使用 XPath 或 CSS 选择器)。②提取页面中的链接,并产生对链接页面的下载请求。
页面解析函数通常被实现成一个生成器函数,每一项从页面中提取的数据以及每个对链接页面的下载请求都由 yield 语句提交给 Scrapy 引擎。
4、运行爬虫
完成代码后,运行爬虫爬取数据,在 shell 中执行如下命令:
scrapy crawl
本例中执行命令为:
scrapy crawl books
执行以下命令将爬取的数据存储到 csv 文件中,命令为:
scrapy crawl books -o books.csv
运行如下:
执行完成后,会将爬取的数据存储到 csv 文件中:
内容如下:
我们发现一个很严重的问题,中文存在编码问题,那我们使用如下方法来解决。
创建项目的 settings.py 文件中,最下方添加如下代码 :
FEED_EXPORT_ENCODING = 'utf-8-sig'
重新执行爬取命令,导出结果如下:
从上述数据可以看出,我们成功地爬取到了 1000 本书的书名和价格信息(50页,每页20项)。
内容参考:
《精通Scrapy网络爬虫》、百度。
END