📘前言
- 🍅 软件版本和环境:
- 🍅 Python 3.8
- 🍅 selenium :4.30
- 🍅 谷歌浏览器:102.0.5005.63
📙 首先解决登录验证问题
🍅 密码登录
登录首页,百度也尝试了很多方法。由于技术不过关,我暂时没解决滑块的问题,留给专业人士解决吧,如果您解决了请,@我啊,我也想学习下。
🍅 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('--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()
def first_login(self, wait_time):
'''
第一次登录,需要人工登录
:param wait_time:
:return:
'''
self.driver.get(self.login_url)
time.sleep(wait_time)
self.driver.get(self.start_url)
def save_cookies(self):
'''
保存浏览器的cookies
:return:
'''
with open("cookies.txt", 'w') as f:
f.write(json.dumps(self.driver.get_cookies()))
if __name__ == '__main__':
C = ScriptCsdn()
C.init_chrome()
C.first_login( 20)
C.save_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:
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.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]
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)
except:
print("图片上传失败{}".format(file))
return None
'''下拉滑条,js 无法生效不知为何,用pyautogui滚动鼠标'''
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())
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滚动鼠标'''
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')
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_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
‘
📙 发布成功示例
虞美人·寄公度 水调歌头·明月几时有
🌎总结
🍅 全部源码放在Git上了,有需自取
- 🚩要有最朴素的生活,最遥远的梦想,即使明天天寒地冻,路遥马亡!
- 🚩如果这篇博客对你有帮助,请 “点赞” “评论”“收藏”一键三连 哦!码字不易,大家的支持就是我坚持下去的动力。
|