用selenium批量删除CSDN博客

目录

需求与背景

本人早年在CSDN写博客,当时CSDN还是很不错的,论坛活跃,广告不多,也没有各种卖课引流的软文,内容上也无先审后发机制。后来发现它经常弹出扫码登陆的对话框,这些我都忍了,直到有一天不登陆连代码都不能复制,这实在违背分享精神,于是决定抛弃CSDN,自建Blog,如今Blog已经迁移到本Hugo平台,想将原有Blog删除,但CSDN无法批量删除,只能一个一个点,我有近170篇文章,一个个手动点太费劲,于是研究了selenium,用python控制浏览器自动删除。 另外我还有一个特殊要求,保留最后发的一篇文章,那是一则对CSDN失望后决定停更的声明。

浏览器驱动下载

可在此页面找到对应浏览器驱动的下载指引,需要下载和当前使用浏览器匹配的版本。
下载好之后将driver解压放到任一PATH环境变量包含的路径下。当然也可以放任意路径,然后在代码中指定路径。

selenium模拟登陆CSDN

selenium的基本操作实际上就是在网页上查找Web元素,然后输入内容(send_key)或点击(click)各种按钮。
以下是我用firefox登陆csdn的代码:

from selenium import webdriver
from time import sleep

usr_name = input('username: ')
pwd = input('password: ')

driver = webdriver.Firefox()

# open website and wait for loading
driver.get("https://mp.csdn.net/mp_blog/manage/article")
sleep(1)

# use xpath to locate login by user & pwd
driver.find_element_by_xpath("/html/body/div[2]/div/div[2]/div[2]/div[1]/div[1]/div[1]/span[4]").click()

# send username & pwd to login
driver.find_element_by_css_selector('[autocomplete="username"]').send_keys(usr_name)
driver.find_element_by_css_selector('[autocomplete="current-password"]').send_keys(pwd)
driver.find_element_by_class_name('base-button').click()

代码执行后会弹出新的窗口进行登陆。由于第一次用selenium,在不断尝试的过程中会重复以上登陆过程,次数多了会出现拖滑块的验证码操作,于是想到能否先手动登陆,然后让selenium连接已有Session。 经研究,Chrome的DevTools Protocol可以轻松实现。

让Chrome重用已有Session

根据DevTools Protocol的操作指引,在CMD命令行下CD到chrome.exe路径后,执行:

chrome.exe --remote-debugging-port=9222  --user-data-dir=C:\temp-chrome-data

执行后会弹出新的Chrome窗口,先在这里面手动完成CSDN的登陆,然后可用如下代码连接这个已打开的会话:

chrome_opts = webdriver.ChromeOptions()
chrome_opts.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
driver = webdriver.Chrome(options=chrome_opts)

不用担心登陆操作之后,就可以专心定位删除按钮进行点击。

最终代码

from selenium import webdriver
from time import sleep
from selenium.webdriver import ActionChains

chrome_opts = webdriver.ChromeOptions()
chrome_opts.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
driver = webdriver.Chrome(options=chrome_opts)

driver.get("https://mp.csdn.net/mp_blog/manage/article")
sleep(6)

# delete all the articles except first one ( my customized requirement )
while True:
    dots_elements = driver.find_elements_by_class_name('el-dropdown-selfdefine')
    if len(dots_elements) <= 1:
        break

    # get article title to be deleted
    title = dots_elements[1].find_element_by_xpath('../../../..//div[1]/p[1]/a').text

    # delete second one
    ActionChains(driver).move_to_element(dots_elements[1]).perform()
    sleep(1)
    
    # delete and confirm
    driver.find_element_by_link_text("删除").click()
    sleep(1)

    driver.find_element_by_class_name('el-button--primary').click()
    sleep(1)
    
    print(f'Deleted: {title}')

代码说明

  • 以上代码会持续寻找所有删除按钮,然后删除第二篇文章直到剩下最后一篇,除了删除动作,还打印出了被删除文章的标题
  • 代码逻辑很简单,主要的难点在于如何定位要操作的元素,需要一些前端知识
  • 随着csdn的维护更新,代码中的css selector和xpath代码可能会失效