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 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 懒到骨子里了,我在CSDN写文章都懒得自己写了,基于selenium模拟写文章 -> 正文阅读

[Python知识库]懒到骨子里了,我在CSDN写文章都懒得自己写了,基于selenium模拟写文章

📘前言

  • 🍅 软件版本和环境:
  • 🍅 Python 3.8
  • 🍅 selenium :4.30
  • 🍅 谷歌浏览器:102.0.5005.63

基于selenium 爬取CSDN,自动写博客


📙 首先解决登录验证问题

🍅 密码登录

登录首页,百度也尝试了很多方法。由于技术不过关,我暂时没解决滑块的问题,留给专业人士解决吧,如果您解决了请,@我啊,我也想学习下。

在这里插入图片描述


🍅 cookies 登录

手动登录保存cookies

  • 我选择了这种方式登录,下面列出了 cookies 登录的相关代码, 如果是首次登录CSDN,那么需要人工登录下,然后会在同级目录下,保存一个cookies.txt 文件,
import pyperclip
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import time
import os, random, shutil
import json
import traceback
from uploads_files import UploadFilesSelenium
from wigits import *


class ScriptCsdn(object):
    def __init__(self):
        self.driver = None
        self.browser_path = r"D:\Document\scrapy\chromedriver_win32\chromedriver_win32\chromedriver.exe"
        self.login_url = "https://passport.csdn.net/login?"
        self.start_url = "https://blog.csdn.net/qq_34414530?spm=1011.2415.3001.5343"
        self.new_article = "https://editor.csdn.net/md/?not_checkout=1&spm=1001.2014.3001.5352"
        self.image_folder = r"D:\Document\source\poem_created"
        self.image_folder_used = r"D:\Document\source\poem_created_used"
        self.mkdir(self.image_folder_used)

    def mkdir(self, path):
        if not os.path.exists(path):
            os.makedirs(path)
            print(path + ' 创建成功')
            return True
        else:
            # 如果目录存在则不创建,并提示目录已存在
            print(path + ' 目录已存在')
            return False

    def init_chrome(self):
        chrome_options = Options()
        # chrome_options.add_argument('--headless')
        chrome_options.add_argument('--no-sandbox')
        chrome_options.add_argument('--disable-dev-shm-usage')
        chrome_options.add_argument('--disable-gpu')
        chrome_options.add_experimental_option('useAutomationExtension', False)
        chrome_options.add_experimental_option('excludeSwitches', ['enable-automation'])
        chrome_options.add_argument("--disable-blink-features=AutomationControlled")
        s = Service(executable_path=self.browser_path)
        self.driver = webdriver.Chrome(service=s)
        self.driver.maximize_window()
        self.driver.delete_all_cookies()
        # print(self.driver.get_window_rect())
        # print(self.driver.get_window_size())


    def first_login(self, wait_time):
        '''
        第一次登录,需要人工登录
        :param wait_time:
        :return:
        '''
        # 记得写完整的url 包括http和https
        self.driver.get(self.login_url)
        # 程序打开网页后20秒内 “手动登陆账户”
        time.sleep(wait_time)
        self.driver.get(self.start_url)

    def save_cookies(self):
        '''
        保存浏览器的cookies
        :return:
        '''
        with open("cookies.txt", 'w') as f:
            # 将cookies保存为json格式
            f.write(json.dumps(self.driver.get_cookies()))
            
if __name__ == '__main__':
    C = ScriptCsdn()
    C.init_chrome()
    C.first_login( 20)
    C.save_cookies()

登录注入cookies

  • 下面列出了 登录时注入cookies 的相关代码
import pyperclip
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import time
import os, random, shutil
import json
import traceback
from uploads_files import UploadFilesSelenium
from wigits import *


class ScriptCsdn(object):
	''' 不相关代码拿掉了'''
    def inject_cookies(self):
        '''
        向浏览器中写入cookies
        :return:
        '''
        with open("cookies.txt", 'r') as f:
            # 使用json读取cookies 注意读取的是文件 所以用load而不是loads
            cookies_list = json.load(f)
            for cookie in cookies_list:
                # 该字段有问题所以删除就可以
                if 'expiry' in cookie:
                    del cookie['expiry']
                self.driver.add_cookie(cookie)

    def main(self):
        self.driver.get(self.start_url)
        self.inject_cookies()
        self.driver.refresh()
            
if __name__ == '__main__':
    C = ScriptCsdn()
    C.init_chrome()
    # C.first_login( 20)
    # C.save_cookies()
    C.main()

📙 模拟写博客的过程

🍅 先说明下,我想干什么

在这里插入图片描述


🍅 新建博客

输入新建博客的URL即可


   self.new_article = "https://editor.csdn.net/md/?not_checkout=1&spm=1001.2014.3001.5352"
    def main(self):
        self.driver.get(self.start_url)
        self.inject_cookies()
        self.driver.refresh()
        self.driver.get(self.new_article)


🍅 需要解决的问题

🍅 随机选择文件夹

  • 那么我需要解决的事:
  • ①,随机选取一个文件夹用来上传CSDN,因为我也不是专业做互联网的开发人员,我没有通过数据库或者临时文件来记录哪些文件夹已经是用过的了,所以我就把这个已经上传过CSDN的古诗词子文件夹移动到另外的文件夹下,等都被移动完了,那也就无法再上传了,我用了shutil库来解决这个问题Python 随机移动文件/文件夹到另一个文件夹
    def random_move_dir(self, source_dir, target_dir):
        '''
        随机移动一个文件夹到另一个文件夹下
        :param source_dir:
        :param target_dir:
        :return:
        '''
        try:
            '''获取当前文件夹下的所有子文件夹名称'''
            images_dirs = []
            for root, dirs, files in os.walk(source_dir):
                for sub in dirs:
                    images_dirs.append(sub)

            sample = random.sample(images_dirs, 1)[0]
            # print(sample)
            source_sub_dir = os.path.join(source_dir, sample)
            print("移动:{}".format(source_sub_dir))
            target_sub_dir = os.path.join(target_dir, sample)
            if os.path.exists(target_sub_dir):
                shutil.rmtree(target_sub_dir, ignore_errors=True)
            '''copy后删除源子文件夹'''
            shutil.copytree(source_sub_dir, target_sub_dir)
            shutil.rmtree(source_sub_dir, ignore_errors=True)
            return target_sub_dir
        except:
            print(traceback.print_exc())

🍅 上传图片的问题

  • 上传图片的时候,我本来是采取全选上传的方式,但是CSDN上图片上传之后显示的顺序,无法保证按照我上传时拍的顺序显示,我只能选择循环,一张图片一张图片的上传 up = UploadFilesSelenium() 类用到的代码在这里selenium从本地上传文件到网页
  • 在这这一步的过程中我解决了一下几个问题:
  • 1,上传图片的标签是input ,无法使用 element.click(),选择了ActionChains 库模拟鼠标的行为
  • 2,上传图片时间不确定,WebDriverWait 库等待上传按钮消失,来确认上传已经结束,再传第二张图片
  • 3,上传完图片后,鼠标定位在这张图片上,那么你就无法继续上传图片,必须要做的是,将鼠标的焦点移动导致这张图片的下面空白区域, last_item = self.driver.find_element(By.XPATH, ".//div[@class='editor']//pre//div[last()]")这行代码会定位到最后一个元素,然后通过pyautogui.press('enter')回车移动光标下移
  • 4,这里我想通过网上大家通用的js来移动下拉滑条,但是无法生效,不知为何(有解决的同志,可以偷偷告诉我啊,万分感谢),最后通过pyautogui来模拟滑轮来解决的这个问题,

在这里插入图片描述

    def upload_picture(self, file):
        '''
        向CSDN上传图片,单张
        :param file:
        :return:
        '''
        try:
            '''点击商团图片按钮'''
            add_photo = self.driver.find_element(By.XPATH, ".//div//button[@data-title='图片 – Ctrl+Shift+G']")
            add_photo.click()
            time.sleep(1)
            choose_photo = self.driver.find_element(By.XPATH, ".//div[@class='uploadPicture']/input")
            ActionChains(self.driver).move_to_element(choose_photo).click().perform()
            time.sleep(1)  # 等待一秒
            '''文件对话框选择文件'''
            up = UploadFilesSelenium()
            up.upload_file(file)
            try:
                WebDriverWait(self.driver, 10).until_not(
                    EC.visibility_of_element_located((By.XPATH, ".//div[@class='uploadPicture']/input")))
                time.sleep(3)  # 等待3秒
            except:
                print("图片上传失败{}".format(file))
                return None

            '''下拉滑条,js 无法生效不知为何,用pyautogui滚动鼠标'''
            # element = self.driver.find_element(By.XPATH, ".//div[@class='editor']//pare<br><hr style="height:2px;border:none;border-top:2px dashed #0066CC;"/><br><br><hr style="height:2px;border:none;border-top:2px dashed #0066CC;"/><br>nt::div[1]")
            # self.driver.execute_script("arguments[0].scrollTop=10000;", element)
            pyautogui.scroll(-1000)  # 向下滚动鼠标
            time.sleep(1)  # 等待一秒
            '''定位到最后一个div标签,解决无法连续上传问题'''
            last_item = self.driver.find_element(By.XPATH, ".//div[@class='editor']//pre//div[last()]")
            ActionChains(self.driver).move_to_element(last_item).click().perform()
            pyautogui.press('enter')
            time.sleep(1)  # 等待一秒
        except:
            print(traceback.print_exc())
  • 🍅 写入其它Markdown语法

  • 比如每次上传一张图片,我都想加一行下划线,直接使用了pyperclip 库和pyautogui 库来解决写入文本类的markdown 内容

在这里插入图片描述

    def write_text(self, text):
        '''
        向CSDN写入文本类型内容
        :param text:
        :return:
        '''
        try:
            pyperclip.copy(text)  # 把指定的路径拷贝到焦点
            pyautogui.hotkey('ctrl', 'v')
            pyautogui.press('enter')
            pyautogui.press('enter')
            time.sleep(1)  # 等待一秒
            '''下拉滑条,js 无法生效不知为何,用pyautogui滚动鼠标'''
            # element = self.driver.find_element(By.XPATH, ".//div[@class='editor']//parent::div[1]")
            # self.driver.execute_script("arguments[0].scrollTop=10000;", element)
            pyautogui.scroll(-1000)  # 向下滚动鼠标
            time.sleep(1)  # 等待一秒
            '''定位到最后一个div标签,解决无法连续上传问题'''
            last_item = self.driver.find_element(By.XPATH, ".//div[@class='editor']//pre//div[last()]")
            ActionChains(self.driver).move_to_element(last_item).click().perform()
            pyautogui.press('enter')
            time.sleep(1)  # 等待一秒
        except:
            print(traceback.print_exc())

📙 发表选择对话框

这个对话框,元素定位比较顺利,CSDN没有采用iframe的方式,无需切窗口,

  • 有一点,因为传的都是图片 发布助手会提示,所以需要check下,然后点两次发表按钮
  • 定位checkbox 标签的时候,让selenium弄你点击label 标签就可以了,这里我浪费了时间,去点击button或者input标签了,不可行的。
  • 有一些标签的xpath ,短时间内我没调出来,我就直接拷贝浏览器定位的xpath了,只有自己定位不到,我才用的,因为浏览器定位的xpath 太长了,太机械了。

在这里插入图片描述

    def main(self):
        self.driver.get(self.start_url)
        self.inject_cookies()
        self.driver.refresh()
        self.driver.get(self.new_article)

        element = WebDriverWait(self.driver, 10).until(
            EC.presence_of_element_located((By.XPATH, ".//div[@class='editor']")))
        print(element)
        editor = self.driver.find_element(By.XPATH, ".//div[@class='editor']/pre")
        editor.send_keys(Keys.CONTROL + 'a')  # CTRL + a :全选
        editor.send_keys(Keys.DELETE)  # 删除
        '''随机选择古诗文件夹'''
        random_folder = self.random_move_dir(self.image_folder,self.image_folder_used)
        files_list = os.listdir(random_folder)
        files_list.sort(key=lambda x: int(re.search("\d+", x).group()))
        print(files_list)
        self.poem_title = files_list[0].split('_')[0]# 取古诗名待用

        '''文章头东西'''
        self.write_text(header)
        self.write_text(line)
        '''循环上传图片'''
        for i in files_list:
            self.upload_picture(os.path.join(random_folder,i))
            self.write_text(line)

        '''尾巴'''
        self.write_text(end)

        '''文章标题先输入'''
        title_input = self.driver.find_element(By.XPATH, ".//div[@class='article-bar__input-box']/input")
        title_input.clear()
        title_input.send_keys(self.poem_title)
        title_input.send_keys(Keys.ENTER)
        time.sleep(2)
        self.publish_config()

        print("**********************写文章完成*******************")

    def publish_config(self):
            '''
            发布文章选择界面
            :return:
            '''
            publish = self.driver.find_element(By.XPATH, ".//button[@class='btn btn-publish']") #点击发送
            publish.click()
            time.sleep(1)  # 等待一秒
            try:# 文章质量不佳,发文助手会提示,再此点击发送发布文章即可
                WebDriverWait(self.driver, 3).until(EC.presence_of_element_located((By.XPATH, ".//div[@class='modal__content']")))
                print("发送助手又顽皮了")
            except:
                publish = self.driver.find_element(By.XPATH, ".//button[@class='btn btn-publish']")
                publish.click()
                time.sleep(1)  # 等待一秒

            '''封面摘要,上一个兄弟标签'''
            dan_tu = self.driver.find_element(By.XPATH, ".//span[contains(text(),'单图')]//preceding-sibling::span")
            ActionChains(self.driver).move_to_element(dan_tu).click().perform()
            time.sleep(1)  # 等待一秒

            '''摘要简介'''
            zhai_yao = self.driver.find_element(By.XPATH, ".//div[@class='d-flex cover-count-1']//textarea")
            zhai_yao.clear()
            zhai_yao.send_keys(self.poem_title)
            time.sleep(1)  # 等待一秒
            '''封面选择,xpath不容易定位,直接用了浏览器中copy 的xpath'''
            feng_mian = self.driver.find_element(By.XPATH, "./html/body/div[1]/div[2]/div/div[1]/div[1]/div[2]/div/div/div[3]/div[1]")
            ActionChains(self.driver).move_to_element(feng_mian).click().perform()
            time.sleep(1)  # 等待一秒

            '''文章标签'''
            wenzhang_label = self.driver.find_element(By.XPATH, ".//button[contains(text(),'添加文章标签')]")
            ActionChains(self.driver).move_to_element(wenzhang_label).click().perform()
            time.sleep(1)  # 等待一秒
            WebDriverWait(self.driver, 3).until(
                EC.presence_of_element_located((By.XPATH, ".//div[@class='mark_selection_box']")))

            vertical_label = ["古诗词", "selenium"]
            for i in vertical_label:
                label = self.driver.find_element(By.XPATH, ".//div[@class='mark_selection_box']//input")
                label.clear()
                label.send_keys(i)
                label.send_keys(Keys.ENTER)
                time.sleep(0.5)  # 等待一秒
            close = self.driver.find_element(By.XPATH, ".//div[@class='mark_selection_box']//button[@title ='关闭']")
            ActionChains(self.driver).move_to_element(close).click().perform()
            time.sleep(1)  # 等待一秒

            '''专栏选择,checkbox,选择的是input标签的父亲标签label'''
            zhuan_lan = self.driver.find_element(By.XPATH, ".//input[@value='诗词鉴赏']//..")
            ActionChains(self.driver).move_to_element(zhuan_lan).click().perform()
            time.sleep(1)  # 等待一秒

            '''文章类型选择'''
            artical_type = self.driver.find_element(By.XPATH, ".//label[@for='original']")
            ActionChains(self.driver).move_to_element(artical_type).click().perform()
            time.sleep(1)  # 等待一秒

            '''发布类型选择'''
            publish_type = self.driver.find_element(By.XPATH, ".//label[@for='public']")
            ActionChains(self.driver).move_to_element(publish_type).click().perform()
            time.sleep(1)  # 等待一秒

            '''内容等级选择'''
            content_level = self.driver.find_element(By.XPATH, ".//label[@for='public_1']")
            ActionChains(self.driver).move_to_element(content_level).click().perform()
            time.sleep(1)  # 等待一秒

            '''滚动滑轮下滑,发布文章按钮可能没加载出来'''
            pyautogui.scroll(-1000)  # 向下滚动鼠标
            time.sleep(1)  # 等待一秒

            # '''保存'''
            # #save = self.driver.find_element(By.XPATH, ".//button[contains(text(),'保存草稿')]")
            # save = self.driver.find_element(By.XPATH, "./html/body/div[1]/div[2]/div/div[1]/div[2]/button[2]")
            # ActionChains(self.driver).move_to_element(save).click().perform()
            # time.sleep(3)  # 等待一秒
            # '''取消'''
            # quxiao = self.driver.find_element(By.XPATH, "./html/body/div[1]/div[2]/div/div[1]/div[2]/button[1]")
            # ActionChains(self.driver).move_to_element(quxiao).click().perform()
            # time.sleep(1)  # 等待一秒
            #
            # WebDriverWait(self.driver, 3).until_not(
            #     EC.visibility_of_element_located((By.XPATH, ".//h3[text()='发布文章']")))<hr style="height:2px;border:none;border-top:2px dashed #0066CC;"/>

            '''发布'''
            save = self.driver.find_elements(By.XPATH, ".//button[text()='发布文章']")[-1]
            ActionChains(self.driver).move_to_element(save).click().perform()
            time.sleep(1)  # 等待一秒
            try:
                WebDriverWait(self.driver, 3).until_not(
                    EC.visibility_of_element_located((By.XPATH, ".//h3[text()='发布文章']")))
            except:
                save = self.driver.find_elements(By.XPATH, ".//button[text()='发布文章']")[-1]
                ActionChains(self.driver).move_to_element(save).click().perform()
                time.sleep(1)  # 等待一秒
            return None

📙 发布成功示例

虞美人·寄公度
水调歌头·明月几时有

在这里插入图片描述

End

🌎总结

23

请添加图片描述

🍅 全部源码放在Git上了,有需自取

7

  • 🚩要有最朴素的生活,最遥远的梦想,即使明天天寒地冻,路遥马亡!

  • 🚩如果这篇博客对你有帮助,请 “点赞” “评论”“收藏”一键三连 哦!码字不易,大家的支持就是我坚持下去的动力。
    18
  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-07-20 18:47:30  更:2022-07-20 18:50:30 
 
开发: 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年12日历 -2024/12/27 2:41:47-

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