基于python框架Scrapy爬取自己的博客内容过程详解


Posted in Python onAugust 05, 2019

前言

python中常用的写爬虫的库常有urllib2、requests,对于大多数比较简单的场景或者以学习为目的,可以用这两个库实现。这里有一篇我之前写过的用urllib2+BeautifulSoup做的一个抓取百度音乐热门歌曲的例子,有兴趣可以看一下。

本文介绍用Scrapy抓取我在博客园的博客列表,只抓取博客名称、发布日期、阅读量和评论量这四个简单的字段,以求用较简单的示例说明Scrapy的最基本的用法。

环境配置说明

操作系统:Ubuntu 14.04.2 LTS

Python:Python 2.7.6

Scrapy:Scrapy 1.0.3

注意:Scrapy1.0的版本和之前的版本有些区别,有些类的命名空间改变了。

创建项目

执行如下命令创建一个Scrapy项目

scrapy startproject scrapy_cnblogs

创建之后查看项目的目录结构如下:

scrapy_cnblogs
 ├── botcnblogs
 │ ├── __init__.py
 │ 
├── items.py  #用于定义抓取内容的实体
 │ 
├── pipelines.py #处理抓取的item的管道
 │ 
├── settings.py #爬虫需要的配置参数在这里
 │ └── spiders
 │ 
 └── __init__.py
 └── scrapy.cfg   #项目的配置文件,可以不去理会,默认即可

其中scrapy.cfg所在的目录为项目的根目录,此文件是项目的配置文件,项目建立后,此文件的内容可以不用理会。其内容如下:

[settings]
default = botcnblogs.settings
[deploy]
#url = http://localhost:6800/
project = botcnblogs

在items.py文件里定义在抓取网页内容中抽象出来的数据结构的定义,由于这里需要博客名称、发布日期、阅读量和评论量这四个字段,定义的Item结构如下:

from scrapy import Item,Field #引入Item、Field
class BotcnblogsItem(Item):
 # define the fields for your item here like:
 title = Field()  #标题
 publishDate = Field() #发布日期
 readCount = Field() #阅读量
 commentCount = Field() #评论数<br data-filtered="filtered"><br data-filtered="filtered">

在pipelines.py里对爬虫抓取到的信息(这里的信息是已经组织好的上面定义的Item对象)进行处理,官方介绍的典型的应用场景为:

  • 清理HTML数据
  • 验证爬取的数据(检查item包含某些字段)
  • 查重(并丢弃)
  • 将爬取结果保存到数据库中

它的定义也很简单,只需要实现process_item方法即可,此方法有两个参数,一个是item,即要处理的Item对象,另一个参数是spider,即爬虫。

另外还有open_spider和close_spider两个方法,分别是在爬虫启动和结束时的回调方法。

本例中处理很简单,只是将接收的Item对象写到一个json文件中,在__init__方法中以“w+”的方式打开或创建一个item.json的文件,然后把对象反序列化为字符串,写入到item.json文件中。代码如下:

# -*- coding: utf-8 -*- 
import json 
class BotcnblogsPipeline(object):
 def __init__(self):
  self.file = open("item.json", "w+") 
 def process_item(self, item, spider):
  record = json.dumps(dict(item), ensure_ascii=False)+"\n" #此处如果有中文的话,要加上ensure_ascii=False参数,否则可能出现乱码
  self.file.write(record)
  return item 
 def open_spider(self, spider):
  pass 
 def close_spider(self, spider):
  self.file.close()

setting.py是爬虫的配置文件,配置爬虫的一些配置信息,这里用到的就是设置pipelines的ITEM_PIPELINES参数,此参数配置项目中启用的pipeline及其执行顺序,以字典的形式存在,{“pipeline”:执行顺序整数}

此例中的配置如下:

SPIDER_MODULES = ['botcnblogs.spiders']
NEWSPIDER_MODULE = 'botcnblogs.spiders'
ITEM_PIPELINES = {
 'botcnblogs.pipelines.BotcnblogsPipeline': 1,
}

准备工作都做好了,爬虫呢,爬虫在哪里实现呢,我们看到项目中有个spiders目录,里面只有一个init.py文件,没错,爬虫文件需要自己创建,就在这个目录下,这里创建一个botspider.py的文件,对网页进行解析的工作就要在这里实现了,此例中定义的爬虫类继承自CrawlSpider类。

定义一个Spider需要如下几个变量和方法实现:

name:定义spider名字,这个名字应该是唯一的,在执行这个爬虫程序的时候,需要用到这个名字。

allowed_domains:允许爬取的域名列表,例如现在要爬取博客园,这里要写成cnblogs.com

start_urls:爬虫最开始爬的入口地址列表。

rules:如果要爬取的页面不是单独一个或者几个页面,而是具有一定的规则可循的,例如爬取的博客有连续多页,就可以在这里设置,如果定义了rules,则需要自己定义爬虫规则(以正则表达式的方式),而且需要自定义回调函数。

代码说话:

#-*- coding:utf-8 -*-
__author__ = 'linuxfengzheng'
from scrapy.spiders import Spider, Rule
from scrapy.selector import Selector
from botcnblogs.items import BotcnblogsItem
from scrapy.linkextractors import LinkExtractor
import re
from scrapy.spiders import CrawlSpider 
class botspider(CrawlSpider):
 name = "cnblogsSpider" #设置爬虫名称 
 allowed_domains = ["cnblogs.com"] #设置允许的域名
 start_urls = [
  "http://www.cnblogs.com/fengzheng/default.html?page=3", #设置开始爬取页面
 ] 
 rules = (
  Rule(LinkExtractor(allow=('fengzheng/default.html\?page\=([\d]+)', ),),callback='parse_item',follow=True),
 ) #制定规则
  def parse_item(self, response):
  sel = response.selector
  posts = sel.xpath('//div[@id="mainContent"]/div/div[@class="day"]')
  items = []
  for p in posts:
   #content = p.extract()
   #self.file.write(content.encode("utf-8"))
   item = BotcnblogsItem()
   publishDate = p.xpath('div[@class="dayTitle"]/a/text()').extract_first()
 
   item["publishDate"] = (publishDate is not None and [publishDate.encode("utf-8")] or [""])[0]
   #self.file.write(title.encode("utf-8"))
   title = p.xpath('div[@class="postTitle"]/a/text()').extract_first()
   item["title"] = (title is not None and [title.encode("utf-8")] or [""])[0]
 
   #re_first("posted @ 2015-11-03 10:32 风的姿态 阅读(\d+")
 
   readcount = p.xpath('div[@class="postDesc"]/text()').re_first(u"阅读\(\d+\)")
 
   regReadCount = re.search(r"\d+", readcount)
   if regReadCount is not None:
    readcount = regReadCount.group()
   item["readCount"] = (readcount is not None and [readcount.encode("utf-8")] or [0])[0]
 
   commentcount = p.xpath('div[@class="postDesc"]/text()').re_first(u"评论\(\d+\)")
   regCommentCount = re.search(r"\d+", commentcount)
   if regCommentCount is not None:
    commentcount = regCommentCount.group()
   item["commentCount"] = (commentcount is not None and [commentcount.encode("utf-8")] or [0])[0]
   items.append(item) 
  return items
  #self.file.close()

因为1.0版和之前的版本在包上有所改变,这里列出此例中所涉及的不同版本的区别

所在包
1.0版本 之前版本
spider scrapy.spiders scrapy.spider
crawlspider scrapy.spiders scrapy.contrib.spiders
linkextractor scrapy.linkextractors scrapy.contrib.linkextractors
rule scrapy.spiders scrapy.contrib.spiders

爬虫思路:

首先进入到我的博客页面http://www.cnblogs.com/fengzheng/,这是我的博客首页,以列表形式显示已经发布的博文,这是第一页,点击页面下面的下一页按钮,进入第二页,页面地址为http://www.cnblogs.com/fengzheng/default.html?page=2,由此看出网站以page作为参数来表示页数,这样看来爬虫的规则就很简单了, fengzheng/default.html\?page\=([\d]+),这个就是爬虫的规则,爬取default.html页面,page参数为数字的页面,这样无论有多少页都可以遍历到。

当然,如果页面数量很少可以在start_urls列表中,将要爬取的页面都列出来,但是这样当博文数量增多就会出现问题,如下:

start_urls = [
  "http://www.cnblogs.com/fengzheng/default.html?page=1",
  "http://www.cnblogs.com/fengzheng/default.html?page=2",
  "http://www.cnblogs.com/fengzheng/default.html?page=3",
 ]

当爬取的网页具有规则定义的情况下,要继承CrawlSpider爬虫类,使用Spider就不行了,在规则定义(rules)时,如果要对爬取的网页进行处理,而不是简单的需要Url,这时,需要定义一个回调函数,在爬取到符合条件的网页时调用,并且设置follow=Ture,定义如下:

rules = (
  Rule(LinkExtractor(allow=('fengzheng/default.html\?page\=([\d]+)', ),),callback='parse_item',follow=True),
 )

回调函数名称为parse_item,在parse_item方法中,就是真正要分析网页html,获取需要的内容的时候了。观察页面,查看需要的信息在什么位置,如图:

基于python框架Scrapy爬取自己的博客内容过程详解

之后,分析网页源码,分析出xpath

基于python框架Scrapy爬取自己的博客内容过程详解

用如下代码找到所有的class为day的div,每一个就是一个博文区域:

posts = sel.xpath('//div[@id="mainContent"]/div/div[@class="day"]')

之后遍历这个集合,获取所需内容,其中注意一下几点:

因为有中文内容,要对获取的内容进行encode("utf-8")编码

由于评论数和阅读量混在一起,要对那个字符串再进行正则表达式提取 

至此,简单的爬虫已经完成,接下来要运行这个爬虫,cd进入到爬虫项目所在的目录,执行以下命令:

scrapy crawl cnblogsSpider

会输出爬取过程信息

基于python框架Scrapy爬取自己的博客内容过程详解

之后会看到,根目录中多了一个item.json文件,cat此文件内容,可以看到信息已经被提取出来:

基于python框架Scrapy爬取自己的博客内容过程详解

点击这里在github获取源码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python操作摄像头截图实现远程监控的例子
Mar 25 Python
Python查询阿里巴巴关键字排名的方法
Jul 08 Python
Python中operator模块的操作符使用示例总结
Jun 28 Python
python遍历 truple list dictionary的几种方法总结
Sep 11 Python
利用aardio给python编写图形界面
Aug 21 Python
python获取代理IP的实例分享
May 07 Python
pyspark 读取csv文件创建DataFrame的两种方法
Jun 07 Python
搭建python django虚拟环境完整步骤详解
Jul 08 Python
python调用c++返回带成员指针的类指针实例
Dec 12 Python
Django对接支付宝实现支付宝充值金币功能示例
Dec 17 Python
Python使用Paramiko控制liunx第三方库
May 20 Python
python缩进长度是否统一
Aug 02 Python
基于python实现的百度音乐下载器python pyqt改进版(附代码)
Aug 05 #Python
使用coverage统计python web项目代码覆盖率的方法详解
Aug 05 #Python
基于python实现的百度新歌榜、热歌榜下载器(附代码)
Aug 05 #Python
selenium2.0中常用的python函数汇总
Aug 05 #Python
Django中使用CORS实现跨域请求过程解析
Aug 05 #Python
Flask使用Pyecharts在单个页面展示多个图表的方法
Aug 05 #Python
PyQt5基本控件使用详解:单选按钮、复选框、下拉框
Aug 05 #Python
You might like
长波知识介绍
2021/03/01 无线电
PHP SPL标准库之接口(Interface)详解
2015/05/11 PHP
详解WordPress中创建和添加过滤器的相关PHP函数
2015/12/29 PHP
既简单又安全的PHP验证码 附调用方法
2016/06/02 PHP
thinkPHP5框架实现基于ajax的分页功能示例
2018/06/12 PHP
jquery文字上下滚动的实现方法
2013/03/22 Javascript
JS对象转换为Jquery对象实现代码
2013/12/29 Javascript
浅析js预加载/延迟加载
2014/09/25 Javascript
jquery分页插件jquery.pagination.js实现无刷新分页
2016/04/01 Javascript
大型JavaScript应用程序架构设计模式
2016/06/29 Javascript
详解js的事件处理函数和动态创建html标记方法
2016/12/16 Javascript
使用JavaScript触发过渡效果的方法
2017/01/19 Javascript
select下拉框插件jquery.editable-select详解
2017/01/22 Javascript
详解vue中computed 和 watch的异同
2017/06/30 Javascript
详解VUE中v-bind的基本用法
2017/07/13 Javascript
JS实现秒杀倒计时特效
2020/01/02 Javascript
JS箭头函数和常规函数之间的区别实例分析【 5 个区别】
2020/05/27 Javascript
微信小程序实现倒计时功能
2020/11/19 Javascript
vue图片裁剪插件vue-cropper使用方法详解
2020/12/16 Vue.js
极简的Python入门指引
2015/04/01 Python
以视频爬取实例讲解Python爬虫神器Beautiful Soup用法
2016/01/20 Python
如何优雅地处理Django中的favicon.ico图标详解
2018/07/05 Python
Python延迟绑定问题原理及解决方案
2020/08/04 Python
pycharm Tab键设置成4个空格的操作
2021/02/26 Python
CSS实现聊天气泡效果
2020/04/26 HTML / CSS
HTML5高仿微信聊天、微信聊天表情|对话框|编辑器功能
2018/04/23 HTML / CSS
专科文秘应届生求职信
2013/11/18 职场文书
违反工作纪律检讨书
2014/02/15 职场文书
土地转让协议书范本
2014/04/15 职场文书
班级旅游计划书
2014/05/03 职场文书
自主招生自荐信范文
2015/03/04 职场文书
2015年妇产科工作总结
2015/05/18 职场文书
2016年党课培训学习心得体会
2016/01/07 职场文书
企业廉洁教育心得体会
2016/01/20 职场文书
《小乌鸦爱妈妈》教学反思
2016/02/19 职场文书
python 模块重载的五种方法
2021/04/24 Python