返回介绍

1.3 编写第一个 Scrapy 爬虫

发布于 2024-02-05 21:13:20 字数 9009 浏览 0 评论 0 收藏 0

为了帮助大家建立对Scrapy框架的初步印象,我们使用它完成一个简单的爬虫项目。

1.3.1 项目需求

在专门供爬虫初学者训练爬虫技术的网站(http://books.toscrape.com)上爬取书籍信息,如图1-1所示。

图1-1

该网站中,这样的书籍列表页面一共有50页,每页有20本书,第一个例子应尽量简单。我们下面仅爬取所有图书(1000本)的书名和价格信息。

1.3.2 创建项目

首先,我们要创建一个Scrapy项目,在shell中使用scrapy startproject命令:

$ scrapy startproject example
New Scrapy project 'example', using template directory
'/usr/local/lib/python3.4/dist-packages/scrapy/templates/project', created in:
/home/liushuo/book/example

You can start your first spider with:
cd example
scrapy genspider example example.com

创建好一个名为example的项目后,可使用tree命令查看项目目录下的文件,显示如下:

随着后面逐步深入学习,大家会了解这些文件的用途,此处不做解释。

1.3.3 分析页面

编写爬虫程序之前,首先需要对待爬取的页面进行分析,主流的浏览器中都带有分析页面的工具或插件,这里我们选用Chrome浏览器的开发者工具(Tools→Developer tools)分析页面。

1.数据信息

在Chrome浏览器中打开页面 http://books.toscrape.com ,选中其中任意一本书并右击,然后选择“审查元素”,查看其HTML代码,如图1-2所示。

图1-2

可以看到,每一本书的信息包裹在<article class="product_pod">元素中:书名信息在其下h3 > a元素的title属性中,如<a href="catalogue/a-light-in-the-attic_1000/index.html"title="A Light in the Attic">A Light in the...</a>;书价信息在其下<p class="price_color">元素的文本中,如<p class="price_color">£51.77</p>。

2.链接信息

图1-3所示为第一页书籍列表页面,可以通过单击next按钮访问下一页,选中页面下方的next按钮并右击,然后选择“审查元素”,查看其HTML代码,如图1-3所示。

图1-3

可以发现,下一页的URL在ul.pager > li.next > a元素的href属性中,是一个相对URL地址,如<li class="next"><a href="catalogue/page-2.html">next</a></li>。

1.3.4 实现Spider

分析完页面后,接下来编写爬虫。在Scrapy中编写一个爬虫,即实现一个scrapy.Spider的子类。

实现爬虫的Python文件应位于exmaple/spiders目录下,在该目录下创建新文件book_spider.py。然后,在book_spider.py中实现爬虫BooksSpider,代码如下:

# -*- coding: utf-8 -*-
import scrapy

class BooksSpider(scrapy.Spider):
 # 每一个爬虫的唯一标识
 name = "books"

 # 定义爬虫爬取的起始点,起始点可以是多个,这里只有一个
 start_urls = ['http://books.toscrape.com/']

 def parse(self, response):
  # 提取数据
  # 每一本书的信息在<article class="product_pod">中,我们使用
  # css()方法找到所有这样的article 元素,并依次迭代
  for book in response.css('article.product_pod'):
    # 书名信息在article > h3 > a 元素的title属性里
    # 例如: <a title="A Light in the Attic">A Light in the ...</a>
    name = book.xpath('./h3/a/@title').extract_first()

    # 书价信息在 <p class="price_color">的TEXT中。
    # 例如: <p class="price_color">£51.77</p>
    price = book.css('p.price_color::text').extract_first()
    yield {
      'name': name,
      'price': price,
    }

  # 提取链接
  # 下一页的url 在ul.pager > li.next > a 里面
  # 例如: <li class="next"><a href="catalogue/page-2.html">next</a></li>
  next_url = response.css('ul.pager li.next a::attr(href)').extract_first()
  if next_url:
    # 如果找到下一页的URL,得到绝对路径,构造新的Request 对象
    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引擎。

1.3.5 运行爬虫

完成代码后,运行爬虫爬取数据,在shell中执行scrapy crawl <SPIDER_NAME>命令运行爬虫'books',并将爬取的数据存储到csv文件中:

  $ scrapy crawl books -o books.csv
  2016-12-27 15:19:53 [scrapy] INFO: Scrapy 1.3.3 started (bot: example)
  2016-12-27 15:19:53 [scrapy] INFO: INFO: Overridden settings: {'BOT_NAME': 'example',
'SPIDER_MODULES': ['example.spiders'], 'ROBOTSTXT_OBEY': True, 'NEWSPIDER_MODULE':
'example.spiders'}
  2016-12-27 15:19:53 [scrapy] INFO: Enabled extensions:
  ['scrapy.extensions.telnet.TelnetConsole',
   'scrapy.extensions.corestats.CoreStats',
   'scrapy.extensions.feedexport.FeedExporter',
   'scrapy.extensions.logstats.LogStats']
  2016-12-27 15:19:53 [scrapy] INFO: Enabled downloader middlewares:
  ['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
   'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
   'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
   'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
   'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
   'scrapy.downloadermiddlewares.retry.RetryMiddleware',
   'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
   'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
   'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
   'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
   'scrapy.downloadermiddlewares.chunked.ChunkedTransferMiddleware',
   'scrapy.downloadermiddlewares.stats.DownloaderStats']
  2016-12-27 15:19:53 [scrapy] INFO: Enabled spider middlewares:
  ['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
   'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
   'scrapy.spidermiddlewares.referer.RefererMiddleware',
   'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
   'scrapy.spidermiddlewares.depth.DepthMiddleware']
  2016-12-27 15:19:53 [scrapy] INFO: Enabled item pipelines:
  []
  2016-12-27 15:19:53 [scrapy] INFO: Spider opened
  2016-12-27 15:19:53 [scrapy] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0
items/min)
  2016-12-27 15:19:53 [scrapy] DEBUG: Telnet console listening on 127.0.0.1:6023
  2016-12-27 15:20:01 [scrapy] DEBUG: Crawled (404)  (referer: None)
  2016-12-27 15:20:02 [scrapy] DEBUG: Crawled (200)  (referer: None)
  2016-12-27 15:20:02 [scrapy] DEBUG: Scraped from <200 http://books.toscrape.com/>
  {'name': 'A Light in the Attic', 'price': '£51.77'}
  2016-12-27 15:20:02 [scrapy] DEBUG: Scraped from <200 http://books.toscrape.com/>
  {'name': 'Tipping the Velvet', 'price': '£53.74'}
  2016-12-27 15:20:02 [scrapy] DEBUG: Scraped from <200 http://books.toscrape.com/>
  {'name': 'Soumission', 'price': '£50.10'}

  ... <省略中间部分输出> ...

  2016-12-27 15:21:30 [scrapy] DEBUG: Scraped from <200
http://books.toscrape.com/catalogue/page-50.html>
  {'name': '1,000 Places to See Before You Die', 'price': '£26.08'}
  2016-12-27 15:21:30 [scrapy] INFO: Closing spider (finished)
  2016-12-27 15:21:30 [scrapy] INFO: Stored csv feed (1000 items) in: books.csv
  2016-12-27 15:21:30 [scrapy] INFO: Dumping Scrapy stats:
  {'downloader/request_bytes': 14957,
   'downloader/request_count': 51,
   'downloader/request_method_count/GET': 51,
 'downloader/response_bytes': 299924,
 'downloader/response_count': 51,
 'downloader/response_status_count/200': 50,
 'downloader/response_status_count/404': 1,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2016, 12, 27, 7, 21, 30, 10396),
 'item_scraped_count': 1000,
 'log_count/DEBUG': 1052,
 'log_count/INFO': 9,
 'request_depth_max': 49,
 'response_received_count': 51,
 'scheduler/dequeued': 50,
 'scheduler/dequeued/memory': 50,
 'scheduler/enqueued': 50,
 'scheduler/enqueued/memory': 50,
 'start_time': datetime.datetime(2016, 12, 27, 7, 19, 53, 194334)}
2016-12-27 15:21:30 [scrapy] INFO: Spider closed (finished)

等待爬虫运行结束后,在books.csv文件中查看爬取到的数据,代码如下:

$ sed -n '2,$p' books.csv | cat -n   # 不显示第一行的csv 头部
  1  A Light in the Attic,£51.77
  2  Tipping the Velvet,£53.74
  3  Soumission,£50.10
  4  Sharp Objects,£47.82
  5  Sapiens: A Brief History of Humankind,£54.23
  6  The Requiem Red,£22.65
  7  The Dirty Little Secrets of Getting Your Dream Job,£33.34

 ... <省略中间部分输出> ...

  995  Beyond Good and Evil,£43.38
  996  Alice in Wonderland (Alice's Adventures in Wonderland #1),£55.53
  997  "Ajin: Demi-Human, Volume 1 (Ajin: Demi-Human #1)",£57.06
  998  A Spy's Devotion (The Regency Spies of London #1),£16.97
  999  1st to Die (Women's Murder Club #1),£53.98
 1000  "1,000 Places to See Before You Die",£26.08

从上述数据可以看出,我们成功地爬取到了1000本书的书名和价格信息(50页,每页20项)。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文