使用selenium自动化爬取腾讯研究院报告
需要用到的库:docx(需要pip install python-docx,不然有些函数无法使用)、re、requests、lxml、selenium、time、os等
项目实现难点:
1、报告标题存在非法字符无法保存,需使用re库中的replace函数进行替换;
2、报告需要存储图片,较为容易的txt写入方法无法满足需求,引入docx库进行存储;
3、在docx中只能添加本地已有图片,因此需要解析图片地址并提前存储图片,做if判断;
4、第一页标签中的next page按钮与第二页标签的next page按钮的存放位置不一样,需要先依次处理第一页、第二页后再进行迭代处理。
导入所需库
from selenium import webdriver
from lxml import etree
import time
import os
import re
import requests
import docx
# from docx import Document #另一种import方式
from docx.shared import RGBColor
from docx.shared import Inches #控制缩进
from docx.shared import Pt # 设置段落格式
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT #WD_ALIGN_PARAGRAPH以前的库是这个已经废弃了,如果你遇到这种案例时建议替换为新的方法库
from docx.oxml.ns import qn #设置字体格式
封装docx文件存储函数
def save_document(title,content,result):
# 创建一个空白Word对象,并设置好字体
file = docx.Document()
file.styles['Normal'].font.name = u'仿宋' # 可换成word里面任意字体
file.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), u'仿宋')
# 创建一个封面 固定用法
p = file.add_paragraph() # 创建一个段落
p.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER # 居中设置
p.paragraph_format.space_before = Pt(180) # 段前距为180
p.paragraph_format.space_after = Pt(30) # 段后距为30
run = p.add_run('腾讯研究院研究报告') # 在段落里添加题目大标题
font = run.font # 设置字体
font.color.rgb = RGBColor(54, 95, 145) # 颜色设置,RGB颜色
font.size = Pt(42) # 字体大小设置,和word里面的字号相对应
# 在封面上添加日期
year = time.strftime("%Y")
month = time.strftime("%m")
day = time.strftime("%d")
today = year + '年' + month + '月' + day + '日' # 构造当天日期
p = file.add_paragraph() # 新建一个段落
p.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
run = p.add_run(today) # 在段落中输入当天日期
font = run.font
font.color.rgb = RGBColor(54, 95, 145)
font.size = Pt(26)
# 添加分页符
file.add_page_break()
# 设置正文标题
# p = file.add_paragraph()
# p.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER # 段落文字居中设置
# run = p.add_run(title)
run.font.color.rgb = RGBColor(54, 95, 145) # 字体颜色设置
run.font.size = Pt(22) # 字体大小设置
# 设置正文
# 判断文档中是否有图片,图片是否与已有爬取图片匹配
for i in range(1,len(content)+1):
#找到当前文章所有图片地址,形成一个列表库
imageurl = tree.xpath('/html/body/section/div/div[1]/div[2]//p/img/@src')
#找到文章中每个P标签中的图片地址
img = result.xpath('/html/body/section/div/div[1]/div[2]/p['+str(i)+']/img/@src')
#将图片地址由列表转换为字符串,方便进行后续的if判断
imgj = ''.join(img)
#进行if判断,如果imgj存在于imageurl的列表中,则在word按顺序添加相应图片
if imgj not in imageurl:
pass
else:
# 根据本地图片名称,从本地添加图片
file.add_picture('D:\\腾讯研究院\\图片库\\'+title+'\\'+imgj.split('/')[-1], width=Pt(400))
# 判断文章内容是否存在,存在则按顺序添加
content1 = result.xpath('/html/body/section/div/div[1]/div[2]/p['+str(i)+']//text()')
if content1 is None:
pass
else:
p = file.add_paragraph()
p.paragraph_format.first_line_indent = Inches(0.2)# 这个控制首行缩进
run.font.size = Pt(16)
content1j = ''.join(content1)
run=p.add_run(content1j)
f = "D:\腾讯研究院\\"
if not os.path.exists(f):
os.makedirs(f)
print("文件不存在,创建")
# 把Word文档保存,注意需提前创建好保存文件夹
file.save(f+str(title)+'.docx')
print('报告生成完毕')
使用selenium执行自动化爬虫
url = ['https://www.tisi.org/?cat=2&page=1','https://www.tisi.org/?cat=2&page=2']
page_text_list = []
#由于“下一页”按钮位置在第一页和第二页有所区别,因此解析第一页及第二页的文章内容,后续按照网页格式进行爬取
for u in url:
bro = webdriver.Chrome(executable_path='./chromedriver')
bro.get(u)
# page_text_list = []
time.sleep(2)
page_text = bro.page_source #当前页面全部加载完毕后对应的所有数据
page_text_list.append(page_text)
#点击下一页(实际上是第三页)
for i in range(2):
next_page = bro.find_element_by_xpath('/html/body/section/div/div[12]/ul/li[8]/a')
next_page.click()
time.sleep(1)
page_text_list.append(bro.page_source)
#创建报告的存储文件夹
file = "D:\\腾讯研究院\\"
if not os.path.exists(file):
os.makedirs(file)
print("文件夹不存在,创建")
#创建报告图片的总存储文件夹
file1 = "D:\\腾讯研究院\\图片库\\"
if not os.path.exists(file1):
os.makedirs(file1)
print("文件夹不存在,创建")
#解析每篇文章的地址并将地址所有的文字存储到docx文件中
for page_text in page_text_list:
tree = etree.HTML(page_text)
cont_list = tree.xpath('/html/body/section/div')
for cont in cont_list:
title = cont.xpath('//*[@class="new-article-title"]//text()')
content = cont.xpath('//*[@class="new-article-title"]/a/@href')
#在首页解析每篇文章的地址
for c in content:
cc = "https:"+c
bro.get(cc)
page_content = bro.page_source
tree = etree.HTML(page_content)
#解析文章标题
atitle = tree.xpath('/html/body/section/div/div[1]/p//text()')
#格式化标题
wanzheng1 = ''.join(atitle)
wanzheng12 = re.sub('[\/::*?"<>|]','-',wanzheng1)
#解析网页p标签,获取P标签列表
acontent = tree.xpath('/html/body/section/div/div[1]/div[2]/p')
#按照报告对爬取图片进行分类
file2 = "D:\\腾讯研究院\\图片库\\"+wanzheng12+"\\"
if not os.path.exists(file2):
os.makedirs(file2)
print("文件不存在,创建")
imageurl = tree.xpath('/html/body/section/div/div[1]/div[2]//p/img/@src')
for iu in imageurl:
response = requests.get(iu)
result = response.content
f=open('D:\\腾讯研究院\\图片库\\'+wanzheng12+"\\"+iu.split('/')[-1],'wb')
f.write(result)
f.close()
save_document(wanzheng12,acontent,tree)
time.sleep(2)
bro.quit()
print('爬取成功')
总结:
1、selenium效率太低;
2、内部迭代次数太多,时间复杂度成倍增加。