阿布云

你所需要的,不仅仅是一个好用的代理。

scrapy简单爬取(一)

阿布云 发表于

p1.png

scrapy 是一个用 python 语言编写的,为了爬取网站数据,提取结构性数据而编写的应用框架。

环境

本文使用的环境:

python 3.5.2

pip 9.0.1

操作系统: Ubuntu 16.04

pythton 环境搭建

在官网下载 Ubuntu 环境下的python3.5的安装包,安装,安装完成后,检查一下 python 的安装情况,一般pyhton安装的时候,pip 也是一起安装好的,如果没有安装完全,再将 pip 也一起安装好。

虚拟环境搭建

现在Ubuntu默认是安装 python2.7 的,避免两个环境之间切换的麻烦,我们安装 python 虚拟环境来解决这个问题。

pip install virtualenv

pip install virtualwrapper

pip list # 查看已安装

virtualenv 能够通过根据不同的 python 版本创建对应不同版本的虚拟环境,virtualwrapper 能够方便的在不同的虚拟环境之间进行切换。安装完成之后,下面我们创建一个 python3.5.2 版本的虚拟环境

source /usr/local/bin/virtualwrapper.sh #这个与 windows 不一样,需要先执行一下脚本才能生效,大家可以打开这个文件看一下

# 创建一个名为 py3Scrapy 的虚拟环境

mkvirtualenv py3Scrapy -p /usr/bin/python3.5

# workon 查看创建好的虚拟环境,虚拟环境的保存路径可以通过 `VIRTUALENV_PYTHON` 来配置

workon

workon py3Scrapy # 进入选择的虚拟环境

如下图所示:

1.png

python的版本也能查看得到,进入虚拟环境之后,在shell前面会出现虚拟环境的名称,退出虚拟环境

deactivate

好了,创建好环境之后,现在来开始我们的 scrapy 之旅吧。

scrapy 环境搭建

scrapy 是基于 twisted 框架的,大家会发现,安装 scrapy 的时候,会需要安装很多包。

pip install scrapy

使用 pip 进行安装,方便,但是这种默认的安装方式,实在官网下载安装包来进行安装的,比较慢,大家可以 使用豆瓣源来进行安装

pip install scrapy -i https://pypi.douban.com/simple

这种方式,下载会非常的快,安装其他的包都可以使用这种方法,但是,如果使用豆瓣源安装的时候,提示找不到符合版本的安装包,那就使用第一种办法进行下载安装,因为豆瓣源可能没有官网那么及早更新。

因为每个人的环境都可能存在差异,安装过程中会出现一些问题。当如果报错,twisted 安装失败的时候,建议从官网下载 twisted 安装包,自行进行安装,安装完成之后,再接着继续上面 scrapy 的安装,安装完成之后,检查一些安装结果

scrapy -h

使用 scrapy 获取某一个文章的信息

好了,环境准备好之后,接下来我们来分析一下伯乐在线的文章网页结构

分析伯乐在线某一篇文章的网页结构和url

伯乐在线网站不需要我们先登录,然后才能访问其中的内容,所以不需要先模拟登录,直接就能访问网页。伯乐在线地址为 https://www.jobbole.com ,这上面的文章质量还是不错的,大家有时间可以看看。

我们随便找一篇文章试图来分析一下,比如 http://blog.jobbole.com/111469/ ,F12进入浏览器调试窗口,从全文分析,比如我们想获取文章标题,文章内容,文章创建时间,点赞数,评论数,收藏数,文章所属类别标签,文章出处等信息

使用 scrapy shell 的方法获取解析网页数据

打开文章链接,我们获取到的是一个html页面,那么如何获取上面所说的那些数据呢,本文通过 CSS 选择器来获取(不了解 CSS selector的小伙伴可以先去熟悉一下 http://www.w3school.com.cn/cssref/css_selectors.asp )。 scrape 为我们提供了一个 shell 的环境,可以方便我们进行调试和实验,验证我们的css 表达式能够成功获取所需要的值。下面启动 scrapy shell

scrapy shell "http://blog.jobbole.com/111469/"

scrapy 将会帮助我们将 http://blog.jobbole.com/111469/ 这个链接的数据捕获,现在来获取一下文章标题,在浏览器中找到文章标题, inspect element 审查元素,如下图所示:

2.png

文章标题为 王垠:如何掌握所有的程序语言 ,从上图获知,这个位于一个 class 名为 entry-header 的 div 标签下的子标签 h1 中,那我们在 scrapy shell 通过 css 选择器来获取一下,如下图所示:

3.png

仔细查看上图,注意一些细节。通过 response.css 方法,返回的结果是一个 selector,不是字符串,在这个 selector 的基础上可以继续使用 css 选择器。通过 extract() 函数获取提取的标题内容,返回结果是一个 list,注意,这里是一个 list ,仍然不是字符串 str,使用 extract()[0] 返回列表中的第一个元素,即我们需要的标题。

但是,如果标题没有获取到,或者选择器返回的结果为空的话,使用 extract()[0] 就会出错,因为试图对一个空链表进行访问,这里使用 extract_first() 方法更加合适,可是使用一个默认值,当返回结果为空的时候,返回这个默认值

extract_first("") # 默认值为 ""

此处仅仅是将 title 标题作为一个例子进行说明,其他的就不详细进行解释了,主要代码如下所示:

title = response.css(".entry-header h1::text").extract()[0]

    match_date = re.match("([0-9/]*).*",

                          response.css(".entry-meta-hide-on-mobile::text").extract()[0].strip())

    if match_date:

        create_date = match_date.group(1)

 

    votes_css = response.css(".vote-post-up h10::text").extract_first()

    if votes_css:

        vote_nums = int(votes_css)

    else:

        vote_nums = 0

 

    ma_fav_css = re.match(".*?(\d+).*",

                          response.css(".bookmark-btn::text").extract_first())

    if ma_fav_css:

        fav_nums = int(ma_fav_css.group(1))

    else:

        fav_nums = 0

 

    ma_comments_css = re.match(".*?(\d+).*",

                               response.css("a[href='#article-comment'] span::text").extract_first())

    if ma_comments_css:

        comment_nums = int(ma_comments_css.group(1))

    else:

        comment_nums = 0

 

    tag_lists_css = response.css(".entry-meta-hide-on-mobile a::text").extract()

    tag_lists_css = [ele for ele in tag_lists_css if not ele.strip().endswith('评论')]

    tags = ','.join(tag_lists_css)

 

    content = response.css(".entry *::text").extract()

解释一下 create_date ,通过获取到的值,存在其他非时间的数据,通过 re.match 使用正则表达式来提取时间。

好了,所有需要的值都提取成功后,下面通过 scrapy 框架来创建我们的爬虫项目。

创建爬虫项目

开始我们的爬虫项目

scrapy startproject ArticleSpider

scrapy 会为我们创建一个名为 ArticleSpider 的项目

进入到 ArticleSpider 目录,使用basic模板创建

scrapy genspider jobbole blog.jobbole.com

创建完成之后,我们使用 pycharm 这个IDE打开我们创建的爬虫项目,目录结构如下所示:

4.png

我们可以在 items.py 里面定义数据保存的格式,在 middlewares.py 定义中间件,在 piplines.py 里面处理数据,保存到文件或者数据库中等。在 jobbole.py 中对爬取的页面进行解析。

下面,我们首先需要做的,就是利用我们编写的 css 表达式,获取我们提取的文章的值。在 jobbole.py 中,我们看到

class JobboleSpider(scrapy.Spider):

    name = 'jobbole'

    allowed_domains = ['blog.jobbole.com']

    start_urls = ['http://blog.jobbole.com/all-posts/']

 

    def parse(self, response):

    pass

scrapy 为我们创建了一个 JobboleSpider 的类,name 是爬虫项目的名称,同时定义了域名以及爬取的入口链接。scrapy 初始化的时候,会初始化 start_urls 入口链接列表,然后通过 start_requests 返回 Request 对象进行下载,调用 parse 回调函数对页面进行解析,提取需要的值,返回 item。

所以,我们需要做的,就是将我们在上一小节编写的代码放在 parse 函数中,同时,将 start_urls 的值,改为上面我们在 scrapy shell 爬取的页面的地址 http://blog.jobbole.com/111469/ ,因为我们这里还没有讲到通过 item 获取我们提取的值,此处你可以通过 print() 函数将值进行打印。在 shell 中启动爬虫(先进入我们的工程目录)

scrapy crawl jobbole

既然我们使用了 pycharm 这个IDE,那么我们就不用 shell 来启动爬虫,在 ArticleSpider 目录下创建一个 main.py 文件

from scrapy.cmdline

import execute

import sys

import os

sys.path.append(os.path.dirname(os.path.abspath(__file__)))

execute(["scrapy", "crawl", "jobbole"])

上面的代码,就是将当前项目路径加入到 path 中,然后通过调用scrapy 命令行来启动我们的工程。然后,通过设置断点调试,一步一步查看我们的提取的变量的值是否正确。

注意:启动之前,将 settings.py 中的 ROBOTSTXT_OBEY 这个参数设置为 False

这样,我们就爬取到了伯乐在线的这一篇文章了。

扩展,爬取所有的文章

既然我们已经能够获取到某一篇文章的数据,那么下面就来获取所有文章的链接。

扩展一:获取所有 url 链接

伯乐在线所有文章链接的入口地址为 http://blog.jobbole.com/all-posts/ ,通过浏览器进入调试模式查看文章列表的链接,如下图所示

5.png

文章链接是在 id 为 archive 的 div 标签下的子 div 标签之下, class 为 post-thumb,这个下面的子标签 a 的 href 属性,仍使用上面说的 scrapy shell 的方法,如下图所示

6.png

可以看出,获得了当前页面所有的文章的 url,这仅仅是当前页面的所有 url,我们还需要获取下一页的 url,然后通过下一页的 url 进入到下一页,获取下一页的所有文章的 url,依次类推,知道爬取完所有的文章 url。

在文章列表的最后,有翻页,分析如下

7.png

下一页是 class 为 next page-numbers 的 a 标签中,如下图

8.png