【Python爬虫】Python编程艺术:轻松实现数据到Word文档的储存

在Python中,我们可能需要将抓取的数据在Word文档中存储和展示,可以使用一些第三方库如python-docx。这个库允许你创建、修改和提取Word文档的元素。请注意,python-docx只能处理.docx格式的文档。下面是如何使用这个库的详细步骤:

  1. 安装库:首先,通过命令pip install python-docx安装库。
  2. 创建文档:使用Document()类来创建一个新的Word文档或者打开一个现有的文档。
  3. 添加段落:通过add_paragraph()方法,你可以在文档中添加新的段落,段落会自动换行。
  4. 添加文本块:使用add_run()方法,在段落中添加文本块(Run对象),文本块不自动换行。
  5. 添加文本:通过add_text()方法,在文本块中添加文本,文本不支持插入换行符。
  6. 添加分隔符:使用add_break()方法,在文本块中添加分隔符,实现段落内的换行。
  7. 添加分页符:使用Document()类的add_page_break()方法,在文档中添加分页符。
  8. 保存文档:使用Document()类的save()方法保存你的文档。

以下是一段示例代码,展示了如何使用这些方法将数据存入Word文档:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
from bs4 import BeautifulSoup
import ssl
import pandas as pd
from urllib.parse import urljoin
import re
from docx import Document
from datetime import datetime

def create_unverified_context():
    """创建不验证服务器证书的HTTPS上下文"""
    return ssl._create_unverified_context()

def get_soup(url, headers, context):
    """获取网页内容并返回BeautifulSoup对象"""
    try:
        # 确保URL以http开头
        url = url.replace('https://', 'http://') if url.startswith('https://') else url
        with requests.get(url, headers=headers, timeout=10, verify=False) as response:
            response.raise_for_status()
            return BeautifulSoup(response.content, "html.parser")
    except requests.exceptions.HTTPError as e:
        print(f"HTTP error: {e.response.status_code} - {e}")
    except requests.exceptions.ConnectionError:
        print("Error connecting to the server.")
    except requests.exceptions.Timeout:
        print("Request timed out.")
    except requests.exceptions.RequestException as e:
        print(f"Request error: {e}")
    return None

def parse_article_soup(article_soup):
    """从BeautifulSoup对象中解析单页文章的详情"""
    article_data = {
        '正文': [],
        '申请人': [],
        '仲裁员': [],
        '书记员': [],
        '案由': None,
        '日期': article_soup.find('meta',attrs={'name':'PubDate'}).get('content'),
        '标题': article_soup.find('meta',attrs={'name':'ArticleTitle'}).get('content'),
        '链接': article_soup.find('meta',attrs={'name':'Url'}).get('content'),
    }
    
    # 获取正文区域内属性style="text-align: center;"的<p>标签之后的所有元素
    article_text_tags = article_soup.select('.news_cont_d_wrap p[style="text-align: center;"]:nth-child(2)~*')

    # 获取所有标签的文本数据
    i, n = 0, 0
    for p in article_text_tags:
        # 检查段落文本中是否包含特定关键词,并据此更新文章数据
        text = re.sub(r'\s+', '', p.get_text(strip=True))
        style_value = p.get('style')
        
        # 获取案由
        if text.startswith('案由'):  #'案由' in re.sub(r'\s+','',p.get_text(strip=True))
            article_data['案由'] = text
            article_data['正文'].append(article_data['案由'])
            n = i
        # 获取仲裁员信息
        elif text.startswith('仲裁员'):
            article_data['仲裁员'].append(text)
        elif text.startswith('书记员'):
            article_data['书记员'].append(text)
        # 处理表格
        elif p.name == 'table':
            rows = p.find_all('tr')
            for row in rows:
                columns = row.find_all('td')
                # 提取单元格数据
                row_data = [column.get_text(strip=True) for column in columns]
                article_data['正文'].append(row_data)
        # 获取案由之前的文本作为“申请人”,并过滤以“案号”开头的文本标签
        elif n == 0 and text and not text.startswith('案号'):
            article_data['申请人'].append(text)
        # 获取案由之后的数据作为“正文”,并过滤<table>标签,和style_value以'right;'结尾的<p>标签
        # style_value的值不是None的情况下,是以'right;'结尾
        elif n != 0 and not p.find('table') and text and not (style_value and style_value.endswith('right;')):
            article_data['正文'].append(text)
        i += 1

    return article_data

def parse_page_data(base_url, headers, context):
    """递归地爬取页面数据直到没有下一页"""
    page_data = []
    curr_page_url = base_url

    # 使用while循环来实现递归爬取
    while curr_page_url:
        # 获取当前页的soup对象
        soup = get_soup(curr_page_url, headers, context)
        if not soup:
            break  # 如果soup为空,直接跳出循环
        
        # 处理当前页的列表内数据
        tag_list = soup.select('div.AllListCon a')
        for tag in tag_list:
            article_url = tag.get('href')
            article_soup = get_soup(article_url, headers, context)
            if article_soup:
                page_data.append(parse_article_soup(article_soup))

        # 查找下一页的链接
        next_page = soup.find('a', class_='next')
        if next_page:
            curr_page_url = next_page.get('href')  # 更新当前页面URL为下一页,继续循环
        else:
            break  # 如果没有下一页,跳出循环
        
    return page_data  # 循环结束后返回data_list

# main函数
def main():
    base_url = 'https://hrss.sz.gov.cn/ztfw/cjjy/wsgk/index.html'
    headers = {'User-Agent': 'Mozilla/5.0 (compatible; YourBot/0.1)'}
    context = create_unverified_context()

    # 获取要储存数据的列表
    data_list = parse_page_data(base_url, headers, context)

    # 创建一个新的Word文档
    doc = Document()
    i = 0

    # 添加数据段落
    for data in data_list:
        # 添加一个段落
        paragraph = doc.add_paragraph()
        # 向段落中添加运行
        i += 1
        paragraph.add_run(f"{i}、{data['日期'][:10]},{data['标题']}___{data['链接'][-12:-5]}").add_break()
        # 正文
        for text in data['正文']:
            paragraph.add_run(text).add_break()
        paragraph.add_run().add_break()
        # 申请人
        for text in data['申请人']:
            paragraph.add_run(text).add_break()
        paragraph.add_run().add_break()        
        # 仲裁员
        paragraph.add_run(data['仲裁员'])
        paragraph.add_run('。')
        paragraph.add_run(data['书记员'])        
        # 在这里插入分页符
        doc.add_page_break()
    
    # 保存文档
    doc_name = f'案例正文_{datetime.now().strftime("%Y%m%d.%H%M%S")}.docx'
    doc.save(doc_name)

    print(f'数据已保存到Word文档:{doc_name}')

if __name__ == "__main__":
    main()

掌握python-docx:深入理解add_run()与add_text()的差异

在使用python-docx库进行Word文档操作时,理解add_run()add_text()方法的区别至关重要。以下是对这两个方法以及其他相关方法的清晰解释:

  • add_paragraph()

    • 创建段落:这个方法用于在Word文档中创建一个新的段落。
    • 特点:每个段落可以可包含多个文本块(Run对象),可自定义样式。
    • 样式多样性:段落的样式可以独立设置,段落之间有明显的间距(自带换行)。
  • add_run()

    • 创建文本块:这个方法属于Paragraph对象,用于在段落中创建一个相同样式的文本块。
    • 连续性:文本块在视觉上是连续的,通过 add_break() 方法可在 Run 对象后添加换行符。
    • 样式多样性:每个 Run 对象允许独立设置样式(如字体、大小、加粗、颜色、下划线等)。Run 对象的样式设置应在 add_run() 之后进行。
  • add_text()

    • 文本添加:这个方法专门用于向段落或文本块中添加文本内容。
    • 参数限制:它只接受字符串(str)类型的参数,非字符串类型如data[0]将导致报错。
    • 使用场景:通常在通过add_run()创建文本块后,使用add_text()向其中填充文本。
  • add_break()

    • 换行操作:这个方法属于Run对象,用于在文本块后添加一个换行符,实现段落内分行。
    • 分行不分段:添加的换行符仅在段落内形成新行,不会创建新的段落。
    • 连续性:多次调用add_break(),也只会在文本块中实现一次换行,保持文本的连续性。
  • add_page_break()

    • 分页符添加:这是Document类的实例方法,用于在文档的指定位置添加一个分页符。
    • 页面控制:通过这个方法,用户可以精确控制文档的页面布局和内容分布。

通过这些方法,python-docx提供了强大的Word文档编辑能力,使得自动化文档生成和管理变得更加高效和灵活。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容