pyspider爬一批文章保存到word中

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

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

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

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

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

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

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

安装:

pip install python-docx

使用方法:

 1 #引入docx扩展包
 2 import docx
 3 
 4 #创建document 对象
 5 document = docx.Document()
 6 
 7 #添加标题,第二个参数是标题的等级
 8 document.add_heading(title, 1)
 9 
10 #添加段落
11 document.add_paragraph(content)
12 
13 #保存成一个docx文件
14 document.save(file_name)

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

第二步:爬一篇文章试试

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

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

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

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

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

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

 1 #!/usr/bin/env python
 2 # -*- encoding: utf-8 -*-
 3 # Created on 2018-04-18 09:42:32
 4 # Project: 1
 5 
 6 from pyspider.libs.base_handler import *
 7 import re, docx
 8 
 9 URL_ARR = {
10     'http://www.shui5.cn/article/FaGuiJieDu/'
11 }
12 
13 class Handler(BaseHandler):
14     crawl_config = {
15     }
16 
17     @every(minutes=24 * 60)
18     def on_start(self):
19         
20         #爬虫入口
21         for each in URL_ARR:
22             self.crawl(each, callback=self.news_list)
23     
24     #新闻列表
25     @config(age=60 * 60) 
26     def news_list(self, response):
27         #当页新闻列表
28         if response.doc('.arcList').html():
29             for each in response.doc('.arcList a').items():
30                 if re.match("http://www.shui5.cn/article/.", each.attr.href, re.U):
31                     self.crawl(each.attr.href, callback=self.news_content)
32         
33         #下一页
34         next_page_index = response.doc('.pagelist.clearfix a').length - 2
35         if u"下一页" in response.doc('.pagelist.clearfix a').eq(next_page_index).text():
36             url = response.doc('.pagelist.clearfix a').eq(total_pages).attr.href
37             self.crawl(url, callback=self.news_list)
38         
39     #新闻内容
40     @config(priority=2)
41     @catch_status_code_error
42     def news_content(self, response):
43         
44         if response.doc('.arcContent').html():
45             document = docx.Document()
46             title = response.doc('.articleTitle h1').text().replace('/', u'')
47             document.add_heading(title, 1)
48             for a in response.doc('.articleDes, .arcContent table p').items():
49                 document.add_paragraph(a.text())
50             file_name = (u'/pyspider/htmlfiles/wordFile/1/' + title + '.docx').encode('gbk')
51             document.save(file_name)
52         else:
53            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的原因了。

 

posted @ 2018-04-18 10:57  大明湖畔的守望者  阅读(521)  评论(0编辑  收藏  举报