最近一直在爬新闻,对于新闻爬取的套路还是比较熟悉的。一个群友发布了一个爬文章入word的任务,我果断接单,自我挑战一下,更何况完成任务还有赏金,哈哈。

任务大概是这样的,有一个文章列表【http://www.shui5.cn/article/Bulletin/】,大约7W的量,每篇文章保存到一个word文件中。

任务比较清晰,观察一下文章内容,发现所有的文章格式都是一致的,这样就比较简单了,只要能爬出一篇文章就搞定了。

但是,现在有一个问题需要优先解决,就是如何用python操作word文档。

第一步:何用python操作word文档

首先明白一点,手动创建的以“.doc”或“.docx”结尾的文件并不是真正的word文件,以word文件的方式打开时会报错的。

网上给的方法是使用python-docx扩展包。

安装:

pip install python-docx

使用方法:

 #引入docx扩展包
import docx #创建document 对象
document = docx.Document() #添加标题,第二个参数是标题的等级
document.add_heading(title, 1) #添加段落
document.add_paragraph(content) #保存成一个docx文件
document.save(file_name)

我的需求是往word文档里添加标题和正文,没有图片,也不需要调整格式,所以有这几个接口就够用了。如果想查看更多接口,可以去这里https://python-docx.readthedocs.io/en/latest/index.html

第二步:爬一篇文章试试

首先分析一下页面结构,页面包含顶部导航、中间的文章列表和底部的分页。

顶部导航是爬虫入口,从这12个分类开始,进入每个分类的文章列表

中部是文章列表,底部是分页,先爬当前页的文章列表,然后从底部进入下一页的文章列表,直到没有下一页的时候。

也可以爬完第一页的时候,分析后续页面的链接特征,同时爬剩下的所有页。但是这样会造成爬虫并发过大,导致一些不可预知的问题。

我采用的是第一种,每次爬一页,然后从“下一页”的链接进入下一个文章列表,直到结束。

先把最后的代码贴出来,再逐一说明

 #!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Created on 2018-04-18 09:42:32
# Project: 1 from pyspider.libs.base_handler import *
import re, docx URL_ARR = {
'http://www.shui5.cn/article/FaGuiJieDu/'
} class Handler(BaseHandler):
crawl_config = {
} @every(minutes=24 * 60)
def on_start(self): #爬虫入口
for each in URL_ARR:
self.crawl(each, callback=self.news_list) #新闻列表
@config(age=60 * 60)
def news_list(self, response):
#当页新闻列表
if response.doc('.arcList').html():
for each in response.doc('.arcList a').items():
if re.match("http://www.shui5.cn/article/.", each.attr.href, re.U):
self.crawl(each.attr.href, callback=self.news_content) #下一页
next_page_index = response.doc('.pagelist.clearfix a').length - 2
if u"下一页" in response.doc('.pagelist.clearfix a').eq(next_page_index).text():
url = response.doc('.pagelist.clearfix a').eq(total_pages).attr.href
self.crawl(url, callback=self.news_list) #新闻内容
@config(priority=2)
@catch_status_code_error
def news_content(self, response): if response.doc('.arcContent').html():
document = docx.Document()
title = response.doc('.articleTitle h1').text().replace('/', u'、')
document.add_heading(title, 1)
for a in response.doc('.articleDes, .arcContent table p').items():
document.add_paragraph(a.text())
file_name = (u'/pyspider/htmlfiles/wordFile/1/' + title + '.docx').encode('gbk')
document.save(file_name)
else:
return {}

特别说明

第46行代码

title = response.doc('.articleTitle h1').text().replace('/', u'、')

这是取文章标题的逻辑,最后有个replace的操作,是因为有的文章标题中有“/”,document.save的时候,会把这个斜杠解析成一级目录,导致保存乱套,所以把标题中的斜杠都替换成顿号了。unicode编码表中没有中文顿号的符号,所以前面加u。

还有50行代码

file_name = (u'/pyspider/htmlfiles/wordFile/1/' + title + '.docx').encode('gbk')

这句是拼word文件名称和保存路径的操作,最后有个encode操作,即编码成gbk,此处是有特殊含义的

我们都知道,在python中默认的编码格式是unicode,而unicode能编码的字符比较少,遇到汉字就无能为力了,只能绕道走,通过把汉字编码成别的编码格式,然后储存第三方编码后的结果。具体的这种第三方编码选谁呢,我在代码第二行已经定义了,即utf-8。所以最后保存的word文件的名称和内容都是utf-8编码的。我的linux的默认编码格式是utf-8(你可以echo $LANG查看一下,或者通过修改/etc/profile文件来修改),所以在linux下是没啥问题的。关键是传输到windows下就出问题了。windows系统默认编码格式是gbk,而word内容的编码是utf-8,所以最后就看到word文件名称乱码而内容正常显示。这也就是我为什么在拼出word文档的标题后,要将它转码为gbk的原因了。

pyspider爬一批文章保存到word中的更多相关文章

  1. python爬取数据保存到Excel中

    # -*- conding:utf-8 -*- # 1.两页的内容 # 2.抓取每页title和URL # 3.根据title创建文件,发送URL请求,提取数据 import requests fro ...

  2. 将爬取的数据保存到mysql中

    为了把数据保存到mysql费了很多周折,早上再来折腾,终于折腾好了 安装数据库 1.pip install pymysql(根据版本来装) 2.创建数据 打开终端 键入mysql -u root -p ...

  3. PHP操作:将数据库中的数据保存到Word、Excel中。

    1.首先要把word.excel表放到文件的根目录下 2.定义了一个word类 <?php class word { function start() { ob_start(); ob_star ...

  4. 1.scrapy爬取的数据保存到es中

    先建立es的mapping,也就是建立在es中建立一个空的Index,代码如下:执行后就会在es建lagou 这个index.     from datetime import datetime fr ...

  5. ffmpeg从AVFrame取出yuv数据到保存到char*中

    ffmpeg从AVFrame取出yuv数据到保存到char*中   很多人一直不知道怎么利用ffmpeg从AVFrame取出yuv数据到保存到char*中,下面代码将yuv420p和yuv422p的数 ...

  6. 将数字n转换为字符串并保存到s中

    将数字n转换为字符串并保存到s中 参考 C程序设计语言 #include <stdio.h> #include <string.h> //reverse函数: 倒置字符串s中各 ...

  7. Android把图片保存到SQLite中

    1.bitmap保存到SQLite 中 数据格式:Blob db.execSQL("Create table " + TABLE_NAME + "( _id INTEGE ...

  8. c# 抓取和解析网页,并将table数据保存到datatable中(其他格式也可以,自己去修改)

    使用HtmlAgilityPack 基础请参考这篇博客:https://www.cnblogs.com/fishyues/p/10232822.html 下面是根据抓取的页面string 来解析并保存 ...

  9. Flask实战第43天:把图片验证码和短信验证码保存到memcached中

    前面我们已经获取到图片验证码和短信验证码,但是我们还没有把它们保存起来.同样的,我们和之前的邮箱验证码一样,保存到memcached中 编辑commom.vews.py .. from utils i ...

随机推荐

  1. 单机安装Hadoop

    单机安装hadoop ------------------------------------------------------------------ 操作系统:centos7 64 位 hado ...

  2. JDK源码解析之Java SPI机制

    1. spi 是什么 SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件. 系统设计的各个抽象,往往 ...

  3. C++ enum的使用

    enum day {Sun,Mon,Tue,Wed,Thu,Fri,Sat};  默认情况下,枚举符的值从0开始,其后值总是前面一个+1.  即Sun=0,Mon=1,Tue=2,Wed=3,Thu= ...

  4. Spring全家桶系列–SpringBoot之AOP详解

    //本文作者:cuifuan //本文将收录到菜单栏:<Spring全家桶>专栏中 面向方面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP). OOP中模块化的关 ...

  5. debounce(防抖动函数)

    短时间内不重复触发一个事件 设置一个门槛值,表示两次 Ajax 通信的最小间隔时间.如果在间隔时间内,发生新的keydown事件,则不触发 Ajax 通信,并且重新开始计时.如果过了指定时间,没有发生 ...

  6. 【代码笔记】Web-HTML-段落

    一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  7. JMeter 检查点之响应断言(Response Assertion)

    检查点之响应断言(Response Assertion)   by:授客 QQ:1033553122 JMeter断言用于对sampler(采样器)进行额外检查,且在相同作用域中,每执行完一个samp ...

  8. JavaScript大杂烩5 - JavaScript对象的若干问题

    1. 类型检查:instanceof与typeof 这是两个相似的操作符,instanceof用于检测函数的实例类型,主要是在面向对象编程中检查new出来的对象类型,需要注意instanceof是检查 ...

  9. [201804012]关于hugepages 3.txt

    [201804012]关于hugepages 3.txt --//有一段时间我一直强调安装oracle一定要配置hugepage,因为现在的服务器内存越来越大,如果还使用4K的页面表,如果内存表占用内 ...

  10. Android (checkBox)

    1.使用 setOnCheckedChangeListener()方法对checkBox进行事件监听 2.重写方法 public void onCheckedChanged(CompoundButto ...