IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> Selenium 爬取微信公众号文章并保存为pdf与长图片 -> 正文阅读

[开发测试]Selenium 爬取微信公众号文章并保存为pdf与长图片

  • 上班搭地铁的时候太无聊了,想在微信看一些感兴趣的学习文章,却不知道如何精准查看。实在无聊的我,查询了一些学习资料,然后做了本期博客。本期博客主要的内容是根据自己输入的关键字,去搜狗微信爬取大量的文章,然后保存为pdf以及长图片,我再保存到手机慢慢看,哈哈哈。
  • 本期博客的代码基本是通用,只需要输入你要学习的内容的关键字,找到保存按钮的位置,自定义保存pdf与长图片的路径,即可得到1000篇对应的公众号文章的pdf以及长图片。
  • 严正声明:本博客仅作学习教程,重在介绍如何使用各种便利的工具来达到学习的目的!不建议大家爬取太大的数据量的文章,虽然一次也最多爬取1000篇。

话不多说,让我步入整体。

1、搭建环境:Selenium+ChromeDriver+pyautogui

1.1 安装包

pip install selenium
pip install pyautogui

1.2、查看你的浏览器的版本

在网址栏输入:chrome://version
在这里插入图片描述

我的浏览器的版本是85.0.4183。

1.3、下载对应版本的ChromeDriver驱动

网址如下:http://chromedriver.storage.googleapis.com/index.html
在这里插入图片描述
因为我的谷歌版本是85.0.4183,所以我下载的ChromeDriver驱动对应的也是85.0.4183版本的。

1.4、设置环境变量

第一步:把下载好的zip压缩包解压,然后把里面的chromedriver.exe复制到谷歌浏览器的安装目录去。忘记谷歌浏览器的安装目录的人可以在1.1的图片那看可执行文件路径那里。
在这里插入图片描述
第二步:复制成功后,把这个目录复制一遍,添加到系统的环境变量里的path。
在这里插入图片描述

2、配置参数,使用驱动打开谷歌浏览器

运行工具:Jupyter NoteBook

from selenium import webdriver
import json

# 设置保存为pdf的参数
appState = """{
    "recentDestinations": [
        {
            "id": "Save as PDF",
            "origin": "local"
        }
    ],
    "mediaSize": {
        "height_microns": 279400,
        "name": "NA_LETTER",
        "width_microns": 215900,
        "custom_display_name": "Letter"
    },
    "selectedDestinationId": "Save as PDF",
    "version": 2,
    "isHeaderFooterEnabled": false
}"""

appState = json.loads(appState)
profile = {"printing.print_preview_sticky_settings.appState": json.dumps(appState)}
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option('prefs', profile)

# 该参数必须存在,不设置会无法使用打印,保存全屏图片等功能
chrome_options.add_argument('--kiosk-printing')

# 打开一个浏览器窗口
driver = webdriver.Chrome(options=chrome_options)

其中,需要注意isHeaderFooterEnabled这个参数,如果为False,则为不打印页眉页脚的意思,因为我后面pdf转全屏图片的时候,存在页眉页脚会影响阅读,就取消了。

3、扫码登录搜狗微信

import time

# 登录搜狗微信
driver.get("https://weixin.sogou.com/")
time.sleep(3)
driver.find_elements_by_xpath('//a[@id="loginBtn"]')[0].click()

在这里插入图片描述

执行上面的代码时,会出现一个二维码,你需要使用微信扫码登录一下。注意,这一步非常重要,如果你没有扫码登录,那么很有可能在接下来爬取文章信息的时候会被检测出是爬虫,会弹出验证而导致爬取失败。而且你不登录,能爬取的学习文章才10页,登录的话可以爬取100页。

4、输入关键字,点击搜索按钮

比如我想学习一些关于selenium的文章,那么我就输入这个关键字就行

# 输入你要收集的学习文章的搜索关键字“XXX”
query = driver.find_element_by_name("query")
query.send_keys("selenium")

# 点击搜索按钮
time.sleep(1)
driver.find_elements_by_xpath('//input[@uigs="search_article"]')[0].click()

5、爬取文章,并保存为pdf

import pyautogui

def scroll_to_bottom(driver):
    js = "return action=document.body.scrollHeight"
    # 初始化现在滚动条所在高度为0
    height = 0
    # 当前窗口总高度
    new_height = driver.execute_script(js)

    while height < new_height:
        # 将滚动条调整至页面底部
        for i in range(height, new_height, 100):
            driver.execute_script('window.scrollTo(0, {})'.format(i))
            time.sleep(0.5)
        height = new_height
        time.sleep(2)
        new_height = driver.execute_script(js)

driver.find_elements_by_xpath('//a[@uigs="article_title_{}"]'.format(0))[0].click()
driver.switch_to.window(driver.window_handles[1])
time.sleep(1)
title = driver.find_elements_by_xpath('//*[@id="activity-name"]')[0].text.replace(" ","-")
scroll_to_bottom(driver)
driver.execute_script('document.title="{}";window.print();'.format(title))
time.sleep(2)
pyautogui.moveTo(1364, 749, 1)
pyautogui.click(button='left')
driver.close()
driver.switch_to.window(driver.window_handles[0])

注意,因为保存为pdf的时候,会跳出弹窗自定义保存的位置,这个弹窗是属于系统自带的,不属于浏览器的,所以selenium是不起作用的。所以我使用了pyautogui来操控鼠标,使得鼠标移动到保存这个位置。也就是说,爬取学习文章并转化为pdf的过程中,需要保持鼠标静止,自己不能动鼠标。这样,pyautogui的这个配置才生效:pyautogui.moveTo(1364, 749, 1)。其中,参数1364与749即是保存按钮的位置。这边建议下载个微信电脑版,然后ALT+A就可以知道保存这个按钮的位置了。注意:这个1364,749只是我电脑跳出弹窗时保存按钮的位置,不同的电脑的保存弹窗的保存按钮的位置都不一样,所以这个地方必须按照自己电脑的保存弹窗的保存按钮实时更改。还有一个特殊情况就是两篇学习文章同名了,就会使得爬取的消息停止下来,我爬取过是不会同名的。如果是重新爬一次,最好把旧的pdf都删了。
在这里插入图片描述

6、将爬取到的pdf转为一张长图片

import fitz  # fitz就是pip install PyMuPDF
import os
import glob
from PIL import Image

def pdf_to_pages_photo(pdfPath, imagePath, split_name):
    
    pdf_context = fitz.open(pdfPath)
    for pg in range(pdf_context.pageCount):
        page = pdf_context[pg]
        rotate = int(0)
        # 每个尺寸的缩放系数为1.3,这将为我们生成分辨率提高2.6的图像。
        # 此处若是不做设置,默认图片大小为:792X612, dpi=96
        zoom_x = 1.33333333  # (1.33333333-->1056x816)   (2-->1584x1224)
        zoom_y = 1.33333333
        mat = fitz.Matrix(zoom_x, zoom_y).preRotate(rotate)
        pix = page.getPixmap(matrix=mat, alpha=False)
        if not os.path.exists(imagePath):  # 判断存放图片的文件夹是否存在
            os.makedirs(imagePath)  # 若图片文件夹不存在就创建
        pix.writePNG(imagePath + '{}{}.png'.format(split_name,str(pg+1)))  # 将图片写入指定的文件夹内

def pages_photo_APhoto(path,split_photo_name,title):
    page_photo_list = []
    image_list = []
    
    page_photo_list = glob.glob('{}{}*.png'.format(path,split_photo_name))
    page_photo_list = [fn.replace(path,'') for fn in page_photo_list]
    # 文件夹名 按数字排序
    page_photo_list.sort(key=lambda x: int(x[len(split_photo_name):-4]))
    
    for pphoto in page_photo_list:
        image_list.append(Image.open(path + os.sep + pphoto))
    
    width = 0
    height = 0
    for img in image_list:
        # 单幅图像尺寸
        w, h = img.size
        height += h
        # 取最大的宽度作为拼接图的宽度
        width = max(width, w)

    # 创建空白长图
    result = Image.new(image_list[0].mode, (width, height), 0xffffff)
    # 拼接图片
    height = 0
    for img in image_list:
        w, h = img.size
        # 图片水平居中
        result.paste(img, box=(round(width / 2 - w / 2), height))
        height += h
    # 保存图片
    result.save('{}{}.png'.format(path,title),quality=95)
    
    # 删除那些片段化的图片,因为已经合成了长图片了
    for pphoto in page_photo_list:
        os.remove(path+pphoto)
    
    time.sleep(1)

# 定义图片存放的位置
imagePath = 'E:\\data\\photo\\'

# 这是刚刚爬取的pdf的下载路径
pdfPath =  'E:\\data\\pdf\\'+title+'.pdf'
        
#将pdf转化为图片,是按页转换
split_photo_name = 'images_'
pdf_to_pages_photo(pdfPath, imagePath, split_photo_name)

# 将按页转换的图片转化为一张长图片,并删除多余的图片
page_title = os.path.split(pdfPath)[1].replace('.pdf','')
pages_photo_APhoto(imagePath,split_photo_name,page_title)

在代码中,有两个地方需要注意:

  • 第一个就是存放下载好的pdf的路径。一般是浏览器的默认下载地址,这个时候,我们就需要去浏览器的设置那里查看自己的下载路径。然后根据实际情况更换掉我的路径E:\data\pdf。
    在这里插入图片描述
  • 第二个就是存放图片的绝对路径,这个自己随便定义就行,一般我建议放在与pdf相近的地方,这样方便全选发到手机在挤地铁无聊的时候学习一下。
    在这里插入图片描述
    至此,所有的注意事项基本都说了,如果大家按照我的介绍去一步步执行,并且不移动鼠标,那么你就可以得到一个pdf以及对应的长屏图片。

7、完整代码

通过上面1-6节的介绍。如果有正确运行,通过观察selenium操作的谷歌浏览器的运行页面,相信大家已经知道整体的流程以及步骤是怎么实现的了,现在我分享一下实现的步骤以及其完整的代码。ps:可以爬取到1000篇学习文章的那种,虽然爬取1000篇可能需要几个小时。

from selenium import webdriver
import json
import time
import pyautogui
import fitz  # fitz就是pip install PyMuPDF
import os
import glob
from PIL import Image

# 设置保存为pdf的参数
appState = """{
    "recentDestinations": [
        {
            "id": "Save as PDF",
            "origin": "local"
        }
    ],
    "mediaSize": {
        "height_microns": 279400,
        "name": "NA_LETTER",
        "width_microns": 215900,
        "custom_display_name": "Letter"
    },
    "selectedDestinationId": "Save as PDF",
    "version": 2,
    "isHeaderFooterEnabled": false
}"""

appState = json.loads(appState)
profile = {"printing.print_preview_sticky_settings.appState": json.dumps(appState)}
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option('prefs', profile)

# 该参数必须存在,不设置会无法使用打印,保存全屏图片等功能
chrome_options.add_argument('--kiosk-printing')

# 打开一个浏览器窗口
driver = webdriver.Chrome(options=chrome_options)

# 登录搜狗微信
driver.get("https://weixin.sogou.com/")
time.sleep(3)
driver.find_elements_by_xpath('//a[@id="loginBtn"]')[0].click()

微信扫码登录之后,更改关键字,保存按钮的pos位置,pdf的存放路径,图片的存放路径为符合自己电脑真实情况,然后静等10多分钟就可以得到1000页学习文章了。
在这里插入图片描述
在这里插入图片描述

def scroll_to_bottom(driver):
    js = "return action=document.body.scrollHeight"
    # 初始化现在滚动条所在高度为0
    height = 0
    # 当前窗口总高度
    new_height = driver.execute_script(js)

    while height < new_height:
        # 将滚动条调整至页面底部
        for i in range(height, new_height, 100):
            driver.execute_script('window.scrollTo(0, {})'.format(i))
            time.sleep(0.5)
        height = new_height
        time.sleep(2)
        new_height = driver.execute_script(js)
        
def get_pdf(n):
    for i in range(n):
        for i in range(10):
            driver.find_elements_by_xpath('//a[@uigs="article_title_{}"]'.format(i))[0].click()
            driver.switch_to.window(driver.window_handles[1])
            time.sleep(1)
            title = driver.find_elements_by_xpath('//*[@id="activity-name"]')[0].text.replace(" ","-")
            scroll_to_bottom(driver)
            driver.execute_script('document.title="{}";window.print();'.format(title))
            time.sleep(2)
            pyautogui.moveTo(1364, 749, 1)
            pyautogui.click(button='left')
            driver.close()
            driver.switch_to.window(driver.window_handles[0])

def pdf_to_pages_photo(pdfPath, imagePath, split_name):
    
    pdf_context = fitz.open(pdfPath)
    for pg in range(pdf_context.pageCount):
        page = pdf_context[pg]
        rotate = int(0)
        # 每个尺寸的缩放系数为1.3,这将为我们生成分辨率提高2.6的图像。
        # 此处若是不做设置,默认图片大小为:792X612, dpi=96
        zoom_x = 1.33333333  # (1.33333333-->1056x816)   (2-->1584x1224)
        zoom_y = 1.33333333
        mat = fitz.Matrix(zoom_x, zoom_y).preRotate(rotate)
        pix = page.getPixmap(matrix=mat, alpha=False)
        if not os.path.exists(imagePath):  # 判断存放图片的文件夹是否存在
            os.makedirs(imagePath)  # 若图片文件夹不存在就创建
        pix.writePNG(imagePath + '{}{}.png'.format(split_name,str(pg+1)))  # 将图片写入指定的文件夹内

def pages_photo_APhoto(path,split_photo_name,title):
    page_photo_list = []
    image_list = []
    
    page_photo_list = glob.glob('{}{}*.png'.format(path,split_photo_name))
    page_photo_list = [fn.replace(path,'') for fn in page_photo_list]
    # 文件夹名 按数字排序
    page_photo_list.sort(key=lambda x: int(x[len(split_photo_name):-4]))
    
    for pphoto in page_photo_list:
        image_list.append(Image.open(path + os.sep + pphoto))
    
    width = 0
    height = 0
    for img in image_list:
        # 单幅图像尺寸
        w, h = img.size
        height += h
        # 取最大的宽度作为拼接图的宽度
        width = max(width, w)

    # 创建空白长图
    result = Image.new(image_list[0].mode, (width, height), 0xffffff)
    # 拼接图片
    height = 0
    for img in image_list:
        w, h = img.size
        # 图片水平居中
        result.paste(img, box=(round(width / 2 - w / 2), height))
        height += h
    # 保存图片
    result.save('{}{}.png'.format(path,title),quality=95)
    
    # 删除那些片段化的图片,因为已经合成了长图片了
    for pphoto in page_photo_list:
        os.remove(path+pphoto)
    
    time.sleep(1)
        
        
if __name__ == "__main__":
    
    # 1、文本框中输入你要收集的学习文章的搜索关键字“XXX”
    query = driver.find_element_by_name("query")
    query.send_keys("selenium")

    # 2、点击搜索按钮
    time.sleep(1)
    driver.find_elements_by_xpath('//input[@uigs="search_article"]')[0].click()
    
    # 3、打印了所有的目标pdf,最多100页,如果不先扫码登录,最多就只能爬取10页
    get_pdf(100)
    
    # 4、获取刚刚爬取的所有pdf的存放路径
    list_pdf = glob.glob('E:\\data\\pdf\\*.pdf')
    
    # 5、定义储存图片的目录
    imagePath = 'E:\\data\\photo\\'
    
    for pdf in list_pdf:
        # 6、循环得到的每一个PDF地址
        pdfPath = pdf
        
        # 7、将pdf转化为图片,是按页转换
        split_photo_name = 'images_'
        pdf_to_pages_photo(pdfPath, imagePath, split_photo_name)

        # 8、将按页转换的图片转化为一张长图片,并删除多余的图片
        title = os.path.split(pdf)[1].replace('.pdf','')
        pages_photo_APhoto(imagePath,split_photo_name,title)

创作不易,如果这篇博客有帮助到你,麻烦你帮忙点个赞加收藏再走。

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-09-09 12:04:57  更:2021-09-09 12:06:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 21:17:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码