爬虫爬取到的数据怎样直接导出 (爬取数据时网址变了怎么办)

最近同事在爬取某网站数据,想将爬取的数据保存为docx。在爬取数据过程中一切很顺利,但是在保存数据时却提示以下错误。

  File "src\lxml\etree.pyx", line 1024, in lxml.etree._Element.text.__set__
  File "src\lxml\apihelpers.pxi", line 747, in lxml.etree._setNodeText
  File "src\lxml\apihelpers.pxi", line 735, in lxml.etree._createTextNode
  File "src\lxml\apihelpers.pxi", line 1540, in lxml.etree._utf8
ValueError: All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters

数据保存使用的是python-docx模块。大致意思是字符不兼容,所有字符串必须与XML兼容。

那么接下来面向百度或谷歌编程,根据百度搜索结果。大致意思是python-docx与中文字符不兼容,需要将字符转为Unicode。让我们先来看看字符的数据内容,和字符数据格式。

def save(doc_title, doc_content_list):
    document = Document()
    # 测试标题
    heading = document.add_heading(doc_title, 0)
    # 居中显示
    heading.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    #打印字符集
    print(chardet.detect(doc_content_list.encode()))
    #打印数据内容
    print(doc_content_list)
    # 测试内容,这里转为Unicode
    document.add_paragraph(doc_content_list)
    # 字符分割,用于保存文件名
    t_title = doc_title.split()[0]
    # 运行
    document.save('*载下**-%s.docx' % t_title)

运行结果如下所示

爬取的网页内容为空的解决办法,爬虫爬的数据怎么保存为excel文档

字符集和数据内容

数据内容好像没问题,字符集为utf-8。

难道是python-docx与中文字符真的不兼容?着手写了一个测试如下

from docx.enum.text import WD_PARAGRAPH_ALIGNMENT  # 用来居中显示标题
from docx import Document

document = Document()
#测试标题,注意这里忘了转为Unicode
heading = document.add_heading("测试标题", 0)
heading.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 居中显示
#测试内容,这里转为Unicode
document.add_paragraph(u'测试内容')
document.save('测试文档.docx')

最后运行一切正常,保存成功。

爬取的网页内容为空的解决办法,爬虫爬的数据怎么保存为excel文档

测试结果

在写测试标题的时候忘了将字符转为Unicode,但是也能够正常保存,说明python-docx是能够支持utf-8字符集。而测试内容转为了Unicode,但是在文档中也能正常显示,说明python-docx在保存Unicode的时候会默认转为utf-8。

按理论上了来说,python-docx在保存数据的时候是没有问题的,那为什么会报错呢?那我们将网站上爬取的数据转为Unicode试试。大致代码如下

def save(doc_title, doc_content_list):
    document = Document()
    # 测试标题
    heading = document.add_heading(doc_title, 0)
    # 居中显示
    heading.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  
    # 测试内容,这里转为Unicode
    document.add_paragraph(json.dumps(doc_content_list))
    # 字符分割,用于保存文件名
    t_title = doc_title.split()[0]
    # 在当前脚本路径存储docx文件
    document.save('*载下**-%s.docx' % t_title)

使用json.dumps将字符串转为Unicode,加上这一步操作后,运行过程中没有任何异常,但是运行结果却不是我们所想要的。大致运行结果如下图所示

爬取的网页内容为空的解决办法,爬虫爬的数据怎么保存为excel文档

运行结果

当场我就纳闷了,怎么标题保存没问题,但是内容保存却是Unicode,按理论来说内容应该会直接转为utf-8啊。

懵逼之后,我整理了下思路:

  1. 数据可以打印,说明数据获取没问题
  2. 数据格式为utf-8
  3. python-docx可以直接保存utf-8数据集,也可以保存Unicode格式
  4. python-docx将数据保存为Unicode不报错,但是显示有问题
  5. python-docx将数据直接以utf-8保存,报错

整理思路,说明我们的数据可能有问题。我们回过头来看下错误提示

All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters

所有字符串必须与XML兼容:Unicode或ASCII,不能是空字节或控制字符。

接下来我们尝试将得到的数据清理下,将所有非utf-8的字符去掉。大致代码如下

from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx import Document
import re
# 清理所有非utf-8的字符
def cleantxt(raw):
    # utf-8字符集范围u4e00-u9fa5 
    fil = re.compile(u'[^0-9a-zA-Z\u4e00-\u9fa5.,,。?“”《》_()!;:]+', re.UNICODE)
    return fil.sub(' ', raw)

def save(doc_title, doc_content_list):
    document = Document()
    # 测试标题
    heading = document.add_heading(doc_title, 0)
    # 居中显示
    heading.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    # 测试内容,清理异常数据
    document.add_paragraph(cleantxt(doc_content_list))
    # 字符分割,用于保存文件名
    t_title = doc_title.split()[0]
    # 在当前脚本路径存储docx文件
    document.save('*载下**-%s.docx' % t_title)

运行一切正常,接下来到了激动人心的时刻了。

爬取的网页内容为空的解决办法,爬虫爬的数据怎么保存为excel文档

运行结果

终于得到了想要的结果,在此记录遇到问题的场景和解决问题的思路和方法和大家共享。