【Free Style】像华为云社区一样优秀,10分钟上手搭建爬虫服务

举报
Sunny 发表于 2017/11/24 16:05:45 2017/11/24
【摘要】 爬虫是时下十分热门的一种程序,谷歌、百度等搜索引擎以及今日头条、即刻等热门应用均建立在爬虫程序的基础上,构成互联网巨大流量的入口。那么现代的爬虫是如何工作,我们自己又如何借助华为云服务搭建自己的爬虫呢?下面我们以爬取华为开发者社区所有的博客为例,利用时下热门的 PySpider 框架快速搭建一个基本的爬虫服务。

pyspider.png


爬虫是时下十分热门的一种程序,谷歌、百度等搜索引擎以及今日头条、即刻等热门应用均建立在爬虫程序的基础上,构成互联网巨大流量的入口。那么现代的爬虫是如何工作,我们自己又如何借助华为云服务搭建自己的爬虫呢?下面我们以爬取华为开发者社区所有的博客为例,利用时下热门的 PySpider 框架快速搭建一个基本的爬虫服务。

爬虫的基本原理

如果把互联网看作是各个站点相互引用、串联形成的一张网,那爬虫顾名思义就是在这张网上穿梭的蜘蛛(Spider)。一个页面作为互联网中的一个节点,很可能会包含有指向其他页面的链接,可以理解为节点之间的连线。爬虫通过遍历节点之间的连线,确定页面之间的网络结构,抓取所需要的信息。


        在开始之前,我们应该清楚一些基本的概念:

  • WWW (World Wide Web, 万维网) 是一个由互相连接的超文本页面组成的系统

  • 每个页面有对应的 URL(Uniform Resource Locator, 网址) 所标记

  • 页面通过 HTTP (Hypertext Transfer Protocol, 超文本传输协议) 传输

  • 网页使用 HTML(HyperText Markup Language, 超文本标记语言) 表示其页面结构


那么具体而言,爬虫程序的运行过程是:

  1. 寻找包含所需信息的页面 URL

  2. 通过 HTTP 获取页面

  3. 从 HTML 中解析出信息

  4. 从中发现更多包含所需信息的 URL,跳转到步骤2


在实现层面上,爬虫程序运行之初,需要提供给它一个 URL 列表,引导爬虫从这些页面开始访问。当爬虫访问这些 URL 时,会识别出页面中的所需的 URL,并将这些 URL 加入到待访问的 URL 列表中。URL 列表中的地址会以一系列策略递归地被爬虫所访问,爬虫会记录这些地址所对应的页面以及一些页面信息。


principle.png

现代爬虫的基本结构现代爬虫的基本结构

PySpider 简介

PySpider 是一个基于 Python 开发的强大爬虫系统,它具有以下特点:

  • 用户使用 Python 编写脚本以控制爬虫的工作流程

  • 包含基于 WebUI 的可视化脚本编辑器、任务监视器、项目管理器及结果预览工具

  • 可以使用 MySQL、MongoDB、Redis、SQLite、ElasticSearch、PostgreSQL 等工具结合 SQLAlchemy 作为存储后端

  • 可以使用 RabbitMQ、Beanstalk、Redis 和 Kombu 作为消息队列

  • 支持任务优先级、任务重试、周期任务、根据页面寿命自动重爬等高级功能

  • 分布式架构,支持 js 解析,支持 Python2 与 Python 3

总结一下,利用 PySpider,可以方便地搭建出专业的爬虫框架。

实战操作

1. 配置华为云服务

作为一个专业稳定的爬虫服务,而不是简单批量下载页面的工具,我们往往需要搭建一个服务器,来让它自动地、定期地去工作,这时一个稳定可信赖的云服务就至关重要了,我们这里就以业界领先的华为云服务为例,搭建爬虫的基础运行环境。

我们首先需要在 https://console.huaweicloud.com/ecm/?locale=zh-cn#/ecs/createVm 申请一个台云服务器。

我的服务器配置为


VM.png

服务器配置

这里我选择了个人更偏好的 CentOS 7.3 系统,下面就以 CentOS 7.3 系统为例,继续接下来的搭建。

2. 环境准备

在安装 PySpider 前,我们可以做一些环境准备,来提升服务的稳定性,这也是在搭建服务时的好习惯。

首先更新 yum,这步会比较漫长

yum update -y

安装 EPEL(Extra Packages for Enterprise Linux),用以安装下面需要的包

yum install epel-release

安装依赖库

yum install python-pip python-devel libxml2-devel python-lxml libxslt-devel openssl-devel -y

升级 pip

pip install --upgrade pip

至此,运行环境及必需的依赖已升级至最新版本。下面我们根据喜好进行一些可选的配置,首先安装 MariaDB 作为爬虫的后端数据库。

yum install mariadb-server mariadb -y

启动 MariaDB 服务

systemctl start mariadb

如果有需要,可以设置数据库 root 用户的密码(your_password 应替换为你的密码),当然也可以不设置:

mysqladmin -u root password "your_password"

这时可以使用如下命令来检查 MariaDB 是否配置成功(如果未设置密码,直接使用 mysql 即可):

mysql -u root -p

然后输入刚才设置的密码,如果没有问题,应该可以看到以 MariaDB [(none)]> 的提示。

此时输入 SHOW DATABASES; 语句,查看所有数据库,如果有类似下面的输出,则配置正常。

MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)

输入 exit 退出,进入下一步。

接下来,安装 Redis,作为消息队列使用。

yum install redis -y

在启动 Redis 之前,需要做一些设置,让 Redis 作为一个服务运行。首先创建一份配置文件:

mkdir -p /etc/redis
   cp /etc/redis.conf /etc/redis/redis.conf

修改 /etc/redis/redis.conf ,将其中的 daemonize 项修改为 yes :

daemonize yes

配置文件路径作为参数,启动 Redis 服务:

redis-server /etc/redis/redis.conf

3. 部署PySpider

在安装 Pyspider 之前,需要先安装 mysql-connector 及 redis 两个依赖,而最新的 mysql-connector 2.2 有 protobuf 的依赖,protobuf 笔者目前还没找到合适的安装方法,所以这里退而求其次,安装不依赖 protobuf 的 mysql-connector 2.1.6

pip install mysql-connector==2.1.6 redis

安装 PySpider

pip install pyspider

创建 PySpider 配置目录

mkdir /etc/pyspider

在 /etc/pyspider 目录下创建 pyspider.conf.json 文件,以下可作为参考:

{  
       "taskdb": "mysql+taskdb://root:your_password@localhost:3306/taskdb",
       "projectdb": "mysql+projectdb://root:your_password@localhost:3306/projectdb",
       "resultdb": "mysql+resultdb://root:your_password@localhost:3306/resultdb",  
       "message_queue": "redis://localhost:6379/db",  
       "webui": {    
           "username": "sunny",    
           "password": "your_user_password",    
           "need-auth": true
          }
   }

其中 taskdbprojectdb 和 resultdb 分别为任务、项目及结果的数据库连接地址,这里我们用一个 MariaDB 服务存储这三类数据,上面的 root 为我们的 MariaDB 用户名,后面 your_password 应替换为之前设置的数据库密码。 message_queue 后应填写消息队列服务的地址,这里我们是将 Redis 做为消息队列使用。 webui 项中的 username 及 password 是用来配置访问 WebUI 时的用户名和密码,也可以不设置用户名和密码,只需将 need-auth 改成 false 即可。

接下来创建一个工作文件夹,并启动爬虫

mkdir ~/pyspidercd ~/pyspider
  pyspider -c /etc/pyspider/pyspider.conf.json

此时访问 http://你的服务器IP地址:5000,应该可以看到 PySpider 的 Dashboard。

如果访问失败,很可能是防火墙组织了发往5000端口的数据包,这时我们需要打开5000端口

iptables -A INPUT -p tcp --dport 5000 -j ACCEPT
   iptables --flush

此时重新启动爬虫,就可以访问 Dashboard 了,我们也可以结合 nohup 让爬虫服务运行在后台:

nohup pyspider -c /etc/pyspider/pyspider.conf.json &

至此 PySpider 服务的部署就完成了。

4. 爬取华为开发者社区

在搭建好服务之后,我们的目标是建立一个华为开发者社区所有文章的数据库,也就是要保存社区中所有的博客文章以及相关的数据。既然要对这些文章下手,那第一件事就是需要找到一个合适的文章列表。一个理想的列表应该具有这些特征:

  • 尽可能多地包含指向文章页面的链接

  • 可以通过跳转到下一页获取到所有文章的 URL

  • 列表根据时间由新到旧排序,方便获取到最新的文章

很幸运,我们发现社区博客页面的首页就有这样一个我们所期待的列表


index.png

博客首页

https://portal.huaweicloud.com/blogs

接下来我们正式开始上手 PySpider。首先输入之前设置的用户名和密码进入 Dashboard,然后点击 Create 新建一个 Project,命名为 huawei_developer,初始 URL 填写我们刚刚找到的列表页面https://portal.huaweicloud.com/blogs,类型选择 Script


create.png

创建 Project

右侧是我们写爬虫代码的编辑区,在 PySpider 中,on_start是整个爬虫的入口

@every(minutes=24 * 60)
       def on_start(self):
            self.crawl('https://portal.huaweicloud.com/blogs', callback=self.index_page)

self.crawl 会获取页面,并调用 callback 来分析响应,@every 装饰器表示 on_start 会每天运行一次确保不会漏掉新的文章。

点击绿色的 Run 按钮,切换到 follow 页面,下面会出现一个链接,就是我们这里首先要爬取的第一个页面,我们这里点击绿色三角按钮


index_step.png

爬取首页

在首页上,我们需要提取两种链接:一是文章的链接,比如https://portal.huaweicloud.com/blogs/b16fc680d01811e7b8317ca23e93a891;二是列表翻到下一页的链接。

我们可以看到,在爬取首页后,默认设置的爬虫在页面上找出了127条链接。而其中我们想要的页面链接实际上只存在于文章列表的区域,下面我们将使用类似于 CSS 选择器的工具来过滤出我们想要的元素。

CSS 选择器是 CSS 用来选择 HTML 中元素的工具,CSS 通过这种简单的语法指定特定的元素并应用一些样式。由于包含信息的元素往往具有不同的样式,所以这里使用 CSS 选择器来过滤元素非常合适。关于 CSS 选择器的更多信息可以参考:

https://www.w3schools.com/cssref/css_selectors.asp


这里我们可以通过 PyQuery 内建的 response.doc 对象使用 CSS 选择器。

PySpider 提供了一个叫做 css selector helper 的工具,利用它我们可以更方便地通过点击元素得到它对应的 css 选择器。切换到 web 页面并点击 enable css selector helper 就可以使用它。


css_helper.png

css selector helper

当光标移到元素上时,对应元素会变成橙色高亮状态。点击元素,一条CSS 选择器信息会出现在页面顶部,你可以进一步编辑来定位需要的元素,然后把 CSS 选择器加在你的代码里。

我们点击一条带链接的文章标题,然后将选择器加在代码里:

@config(age=10 * 24 * 60 * 60)
   def index_page(self, response):
        for each in response.doc('a.common-blog-title').items():
            self.crawl(each.attr.href, callback=self.detail_page)

在提取到文章链接的同时,我们也要考虑翻页操作。这里可以用同样的思路得到指向下一页的链接。值得注意的是,最后一页的页面上没有对应的翻页控件,因此需要做一个额外的判断,在有翻页按钮的情况下才向后翻页。此外,我们解析文章列表页的函数是 index_page 本身,所以翻页的回调函数应设为 self.index_page,修改后的代码为:

@config(age=10 * 24 * 60 * 60)
   def index_page(self, response):
        for each in response.doc('a.common-blog-title').items():
            self.crawl(each.attr.href, callback=self.detail_page)
        next = response.doc('.ucd-pager-next > a')    if next:
        self.crawl(next.attr.href, callback=self.index_page)

再次点击 run,然后进入 follow 页,选择一个文章链接,点击三角进入详情。

我们可以加一些键值来提取和保存更多的信息:

@config(priority=2)
   def detail_page(self, response):
        return {
                "url": response.url,
                "title": response.doc('.cloud-blog-detail-title').text(),        
                "author": response.doc('.sub-content-username').text(),        
                "release_time": response.doc('.article-write-time').text()[4:],        
                "view_time": response.doc('.common-blog-eye').next().text(),        
                "comment_time": response.doc('.common-blog-bubbling').next().text(),        
                "tags": [i.text() for i in response.doc('.blog-menu-footer > a').items()],        
                "summary": response.doc('.cloud-blog-detail-summary-tag').text(),        
                "content": response.doc('#blogContent').html()
        }

在原先只保存 url 和 title 的基础上,我们把文章相关的作者、发布时间、浏览次数、评论数、标签、摘要和正文都从页面上提取出来,具体的获取细节和上面类似,这里就不展开了。点击 run 可以看到提取的效果。


preview.png

预览提取的数据

从预览来看,结果还是很符合我们的预期的。完成代码编辑和测试后,别忘了点右上角的 save,然后回到 Dashboard,将项目对的 status 改成 DEBUG 或者 RUNNING,然后点击 Run,爬虫就开始每天按计划进行爬取并更新数据啦。

任务完成后点击 Results 可以看到爬虫保存的数据,可以导出并做后续的加工处理。由于我们使用了 MariaDB 保存结果,实际上后续的数据处理过程也可以直接连接数据库获取数据。

总结

至此,我们的 PySpider 爬虫实战入门项目就完成了。华为开发者社区是一个开放的平台,因此数据获取也并没有受到太多阻碍,然而在实际的运用中,会遇到很多具有反爬虫策略的网站。道高一尺,魔高一丈,我们用上 ip 代理、模拟登陆、验证码识别、无头浏览器等等技术手段和网站维护人员斗智斗勇,还是有办法突破他们设置的封锁的。

这篇博文只是一个系列的开篇,后续我会为大家总结应对反爬虫策略的一些方法,以及数据分析和处理的技巧,欢迎大家一起交流。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

举报
请填写举报理由
0/200