Scrapy 探索:使用 Scrapy 爬取自己的 CSDN 博客

来源:互联网 发布:旅游cms系统 编辑:程序博客网 时间:2024/04/29 19:55

一、引言

在学习了 Python 之后,曾经跟随着 《Web Scraping with Python》的作者使用 urllib 和 BeautifulSoup 写过一个爬取自己 CSDN 博客的爬虫,相关博客如下:
Web Scraping with Python: 使用 Python 爬 CSDN 博客

而之后《Web Scraping with Python》的作者用仅仅三四页的篇幅简单介绍了下 Scrapy,而就是这短少的三四页篇幅,打开了我走向 Scrapy 的道路。

而这篇博客,就是用 Scrapy 通过 css 和 xpath 两种书写选择器的方式来实现 CSDN 博客的文章列表信息的爬取。

二、Scrapy 简介

Scrapy 是一个为了爬取网站数据,提取结构性数据而编写的应用框架。其提供了非常丰富实用的特性,能够使得我们编写自己的爬虫程序更加的轻松惬意(比如说 scrapy shell)。

想要了解 Scrapy 的同学可以看看官方文档:
Scrapy中文文档(已经落后于最新文档,并且 demo 也无法成功运行)
Scrapy英文文档(建议看这个)

接下来简单介绍下我们使用
scrapy startproject blog创建项目之后的文件结构:
directory

参考官方文档,可得知以下文件:

文件 备注 blog (手动创建)scrapy startpoject 命令创建的 scrapy 项目工程文件 blog/spiders/ (添加代码)放置 spiders 代码的目录,我们的爬虫代码文件就放到这里 blog/item.py (未使用到)项目的 item 文件 blog/pipelines.py (未使用到)项目的 pipelines 文件 blog/settings.py (未使用到)项目的设置文件

详细的 Scrapy 细节可以参看 Scrapy 的官方文档,建议先看英文版的入门教程,然后高深的内容再看中文版的,这样比较快速一些。

二、选择器(Selectors)的书写

我们想要从博客里面抓取到文章列表中每个文章的以下内容:

  1. 文章标题(title)
  2. 阅读量(view)
  3. 评论量(comments)

于是,我们需要做的,就是使用选择器表达式,在返回的 response 对象中找到这些元素。

这里,我通过 css 和 xpath 两种方式进行了查找。(这里使用 scrapy shell 进行选择器的调试,不了解 scrapy shell 用法的同学可以参看官方文档)

1. css 方式
我们可以通过 Chrome 强大的调试功能,通过 Copy selector 获取某个元素的 css 选择器表达式,然后经过 scrapy shell 调试,写出我们需要的 css 选择器表达式。

# title''.join(article.css('span.link_title a:not(font)::text').extract()                                ).replace('\r\n', '').strip()# viewarticle.css('span.link_view::text').extract_first().replace('(', '').replace(')', '')# commentarticle.css('span.link_comments::text').extract_first().replace('(', '').replace(')', '')

一般来说,我们可以使用以下的方法来写 css 表达式:

  1. Chrome Copy selector 获取 css 选择器表达式(以供参考)
  2. scrapy shell 进行测试
  3. 如有特殊情况,可以参考 CSS 选择器参考手册

以上三个步骤,基本上已经可以很快速并且准确的写出 css 选择器表达式了。

2. XPath 方式
同样的,我们也可以通过 Chrome 的开发者模式 Copy XPath 获取某个元素的 XPath 表达式,再在 scrapy shell 中进行验证,最后写出我们所需要的最终的 XPath 选择器表达式。

# title''.join(article.xpath('.//span[@class="link_title"]/a/text()'                     ).extract()).replace('\r\n', '').strip()# viewarticle.xpath('.//span[@class="link_view"]/text()'                                      ).extract_first().replace('(', '').replace(')', '').strip()# commentarticle.xpath('.//span[@class="link_comments"]/text()'                                         ).extract_first().replace('(', '').replace(')', '').strip()

一般来说,我们可以按照以下步骤书写 XPath 选择器表达式:

  1. Chrome Copy XPath 进行参考
  2. scrapy shell 中进行测试
  3. 如有特殊情况,可以参考 XPath 语法

至此,我们已经解决了书写一个爬虫程序最困难的部分了,也就是数据的抓取。

书写选择器表达式确实是一个比较枯燥乏味的工作,但是有了 Chrome 的帮助,再加上强大的 scrapy shell 的即时调试,我们还是可以很轻松惬意的写出来的。

三、自定义 Spider 参数

要想达到可以爬取指定用户的 CSDN 博客的功能,我们需要用户输入的一个用户名参数,比如说我的博客的用户名就是:

u012814856

我们可以简单的使用这个用户名拼凑出任何一个用户的博客页面:

http://blog.csdn.net/u012814856

也就是说,我们需要我们的爬虫程序能够接受一个参数。

幸运的是,Scrapy 支持 Spider 的参数,只需要我们定义一个用于中转存储的 init 函数:

 # 默认传入本人的博客名称,也可以使用 Spider 参数指定名称 # scrapy crawl blog-xpath -a user=xxx -o blog-xpath.xml def __init__(self, user='u012814856', *args, **kwargs):     super(BlogSpiderXPath, self).__init__(*args, **kwargs)     self.start_urls = [         'http://blog.csdn.net/%s' % user     ]

注意,这里我让 BlogSpiderXPath 这个对象构造的时候可以多接收一个 user 参数,这个参数被默认为 u012814856,也就是我自己的博客,我们可以通过以下两种方式运行这个爬虫程序:

# 默认爬取我的博客scrapy crawl blog-xpath# 爬取 xxx 用户的博客scrapy crawl blog-xpath -a user=xxx

相关内容可以查看 Spider arguments

四、代码展示

最后,我们通过只在 blog/spiders 下添加了两个文件 blog-css.py 和 blog-xpath.py 就实现了 css 和 xpath 两种方式爬取博客的功能。

其中,blog-css.py 代码如下:

import scrapyclass BlogSpiderCss(scrapy.Spider):    name = 'blog-css'    # 默认传入本人的博客名称,也可以使用 Spider 参数指定名称    # scrapy crawl blog-css -a user=xxx -o blog-css.xml    def __init__(self, user='u012814856', *args, **kwargs):        super(BlogSpiderCss, self).__init__(*args, **kwargs)        self.start_urls = [            'http://blog.csdn.net/%s' % user        ]    def parse(self, response):        for article in response.css('div.article_item'):            yield {                # 这里要区分该标题是否置顶,如果是置顶的,解析出来就会有两个元素                # ['\r\n        ', '\r\n        思考的救赎(二):三消游戏功能完善            \r\n        ']                # 此时使用 ''.join 即可转换为 str 然后去除空白元素即可                'title': ''.join(article.css('span.link_title a:not(font)::text').extract()                                ).replace('\r\n', '').strip(),                'view': article.css('span.link_view::text').extract_first().replace('(', '').replace(')', ''),                'comment': article.css('span.link_comments::text').extract_first().replace('(', '').replace(')', ''),            }            next_page = response.css('#papelist > a:nth-last-child(2)::attr(href)').extract_first()            if next_page is not None:                yield scrapy.Request(response.urljoin(next_page))

由于 blog-xpath.py 与 blog-css.py 代码逻辑相同,不再赘述,感兴趣的可以下载我的代码观看。

通过在项目根目录下运行:

scrapy crawl blog-xpath -o blog-xpath.xml

我们可以获取到爬取到内容的 blog-xpath.xml 文件信息:

blog-xpath.xml

五、总结

学习 Scrapy 的过程,一开始是非常欣喜的,学到了 Selectors 的时候,又会觉得有点懊丧,但坚持下来了之后,又会觉得拨云见日又发现了一个美好的世界。

或许这就是学习的乐趣。

Scrapy 是个非常强大,社区也非常完善的框架,即使作为兴趣来学习,也是一种不错的体验。

本项目仅仅是个非常简单的示例,甚至连 item 和 pipelines 都未使用到。还有更深的内容有待我自己探索了。

想要获取本项目工程文件的同学可以点击这里(其中的 4.blog 文件夹):
wangying2016/LearnScrapy

最后

To be Stronger : )

阅读全文
0 0