在Python中,我们可能需要将抓取的数据在Word文档中存储和展示,可以使用一些第三方库如python-docx。这个库允许你创建、修改和提取Word文档的元素。请注意,python-docx只能处理.docx格式的文档。下面是如何使用这个库的详细步骤:
-
安装库:首先,通过命令
pip install python-docx
安装库。 -
创建文档:使用
Document()
类来创建一个新的Word文档或者打开一个现有的文档。 -
添加段落:通过
add_paragraph()
方法,你可以在文档中添加新的段落,段落会自动换行。 -
添加文本块:使用
add_run()
方法,在段落中添加文本块(Run对象),文本块不自动换行。 -
添加文本:通过
add_text()
方法,在文本块中添加文本,文本不支持插入换行符。 -
添加分隔符:使用
add_break()
方法,在文本块中添加分隔符,实现段落内的换行。 -
添加分页符:使用Document()类的
add_page_break()
方法,在文档中添加分页符。 -
保存文档:使用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文档编辑能力,使得自动化文档生成和管理变得更加高效和灵活。