Twitter 自动上传图文
这篇文章会使用 Python 的 Selenium 函数库,实作一个可以自动登录 Twitter,自动上传图片以及发布 Twitter 的爬虫,同时也会让 selenium 所做出的爬虫的程序在背景运作,不会影响到其他视窗的工作。
快速导览:
执行 selenium 会启动 chromedriver,所以所以请使用本机环境 ( 参考:使用 Python 虚拟环境 ) 或使用 Anaconda Jupyter 进行实作 ( 参考:使用 Anaconda ) 。
设定 selenium 爬虫环境
由于 Twitter 本身也有做“基本”的反爬虫 ( 辨识浏览器 Headers 信息 ),所以需要提供伪装后的信息。
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15"
opt = webdriver.ChromeOptions()
driver = webdriver.Chrome('./chromedriver', options=opt)
# 清空 window.navigator
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""
})
点击登录按钮
用 Chrome 打开 Twitter 的首页。
Twitter:https://twitter.com/
将鼠标移动至右方的“登录”的位置,按下右键,选择“检查”,可以看见登录按钮是一个 div 和两个 span 放在一个 a 的 tag 里的结构,a 的 tag 具有 href 为“/login”的属性。
接续上方的程序,撰写下方的程序码,执行后会先将视窗往下卷动 ( 登录按钮露出 ),接着自动点击登录按钮。
driver.get('https://twitter.com')
sleep(2)
driver.execute_script(f'window.scrollTo(0, 200)') # 自動往下捲動 200px
login = driver.find_element(By.CSS_SELECTOR, 'a[href="/login"]') # 取得登入按鈕
login.click() # 點擊登入按鈕
输入 Email 账号
登录后,画面中会出现输入登录信息的视窗,点击输入 email 的字段,按下右键,选择“检查”,找到“输入文字”的 input tag,以及“下一步”的按钮 div tag,记下 input 的 autocomplete 属性和 div 的 role 属性。
注意,如果发现 tag 里有很多无意义英文数字组成的 class、id 或属性,往往是系统乱数产生,如果使用爬虫爬取这些自动产生的名称,可能会发生“找不到”的错误,因此要寻找有意义的名称。
接续上方的程序继续撰写,先抓取并自动输入 email,然后再抓取 div 元素,由于属性 role 为 button 的 div 有好几个,所以使用内容判断,如果 div 的内容为“下一步”或“Next”表示可以点击。
由于爬虫在打开浏览器的状态下,Twitter 界面会自动变成中文,背景执行时会变成是英文,所以用 or 做判断。
sleep(2) # 等待兩秒,讓網頁載入完成
# 取得輸入 email 的輸入框
username = driver.find_element(By.CSS_SELECTOR, 'input[autocomplete="username"]')
username.send_keys('你的 email') # 輸入 email
print('輸入 email 完成')
# 取得畫面上所有按鈕 ( 使用 elements )
buttons = driver.find_elements(By.CSS_SELECTOR, 'div[role="button"]')
for i in buttons:
if i.text == '下一步' or i.text == 'Next':
i.click() # 如果按鈕是「下一步」或「Next」就點擊
print('點擊下一步')
break
避开安全性页面
由于是使用爬虫登录,所以 Twitter 基于安全性考量,“有可能”会额外弹出一个视窗,要求输入 Twitter 账号做进一步确认,仿照上面的做法,找到对应元素 HTML 代码。
接续上方的程序继续撰写,使用 try 和 except 的做法,在没有安全性页面时,直接等待两秒就继续,如果有安全性页面时,自动输入账号并进行下一步。
sleep(2) # 等待兩秒頁面載入後繼續
try:
check = driver.find_element(By.CSS_SELECTOR, 'input[autocomplete="on"]')
check.send_keys('你的帳號') # 輸入帳號
buttons = driver.find_elements(By.CSS_SELECTOR, 'div[role="button"]')
for i in buttons:
if i.text == '下一步' or i.text == 'Next':
i.click() # 如果按鈕是「下一步」或「Next」就點擊
print('驗證使用者帳號,點擊下一步')
break
sleep(2) # 等待兩秒頁面載入後繼續
except:
print('ok')
sleep(2) # 如果沒有出現安全性畫面,等待兩秒頁面載入後繼續
输入密码,登录 Twitter
输入 email 或通过安全性检查页面后,会出现密码输入的画面,仿照上面的做法,找到对应元素 HTML 代码。
接续上方的程序继续撰写,抓取密码输入的 input 字段,填入密码后抓取并点击登录的按钮。
pwd = driver.find_element(By.CSS_SELECTOR, 'input[autocomplete="current-password"]')
pwd.send_keys('你的密碼')
print('輸入密碼')
buttons = driver.find_elements(By.CSS_SELECTOR, 'div[role="button"]')
for i in buttons:
if i.text == '登入' or i.text == 'Log in':
i.click()
print('點擊登入')
break
上传图片并发布 Twitter
登录后,仿照上面的做法,找到输入文字、上传图片的按钮和推文按钮的网页元素 HTML。
输入文字的字段,是使用 div 和 span 组成。
上传图片的按钮虽然是 div,但本质上仍然是使用 type 为 file 的 input 元素。
发布 Twitter 的按钮跟之前一样都是 role 为 button 的 div。
接续上方的程序继续撰写,先在输入文字的字段填上文字,接着直接针对 input 字段提供图片在电脑中的“绝对路径”,完成后点击推文按钮,程序执行后就会自动上传图片,并发布 Twitter。
自动发布的 Twitter:链接
sleep(2)
textbox = driver.find_element(By.CSS_SELECTOR, 'div[role="textbox"]')
textbox.send_keys('Hello World!I am Robot~ ^_^') # 在輸入框輸入文字
print('輸入文字')
sleep(1)
imgInput = driver.find_element(By.CSS_SELECTOR, 'input[data-testid="fileInput"]')
imgInput.send_keys('/Users/oxxo/Desktop/oxxo.png') # 提供圖片絕對路徑,上傳圖片
print('上傳圖片')
sleep(1)
buttons = driver.find_elements(By.CSS_SELECTOR, 'div[role="button"]')
for i in buttons:
if i.text == '推文' or i.text == 'Tweet':
i.click() # 點擊推文按鈕
print('推文完成')
break
sleep(1)
driver.close() # 關閉瀏覽器視窗
让爬虫在背景执行
程序全部完成后,可以额外设定“--headless”,让爬虫程序在“背景执行”,避免打开浏览器视窗时,影响其他视窗的工作 ( 如果将爬虫的视窗缩小,则爬虫会发生错误,无法和其他视窗同时工作 )
小结
透过 Twitter 爬虫的自动上传图文,可以练习到使用 Selenium 函数库操作“背景执行”以及“上传图片”,如果再搭配一些时间的排程,就能做到全自动定时发 Twitter 的效果啰!
完成程序码
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15"
opt = webdriver.ChromeOptions()
opt.add_argument('--headless')
opt.add_argument('--user-agent=%s' % user_agent)
driver = webdriver.Chrome('./chromedriver', options=opt)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""
})
driver.get('https://twitter.com')
sleep(2)
driver.execute_script(f'window.scrollTo(0, 200)')
login = driver.find_element(By.CSS_SELECTOR, 'a[href="/login"]')
login.click()
sleep(2)
username = driver.find_element(By.CSS_SELECTOR, 'input[autocomplete="username"]')
username.send_keys('你的 email')
print('輸入 email 完成')
buttons = driver.find_elements(By.CSS_SELECTOR, 'div[role="button"]')
for i in buttons:
if i.text == '下一步' or i.text == 'Next':
i.click()
print('點擊下一步')
break
sleep(2)
try:
check = driver.find_element(By.CSS_SELECTOR, 'input[autocomplete="on"]')
check.send_keys('你的帳號')
buttons = driver.find_elements(By.CSS_SELECTOR, 'div[role="button"]')
for i in buttons:
if i.text == '下一步' or i.text == 'Next':
i.click()
print('驗證使用者帳號,點擊下一步')
break
sleep(2)
except:
print('ok')
sleep(2)
pwd = driver.find_element(By.CSS_SELECTOR, 'input[autocomplete="current-password"]')
pwd.send_keys('你的密碼')
print('輸入密碼')
buttons = driver.find_elements(By.CSS_SELECTOR, 'div[role="button"]')
for i in buttons:
if i.text == '登入' or i.text == 'Log in':
i.click()
print('點擊登入')
break
sleep(2)
textbox = driver.find_element(By.CSS_SELECTOR, 'div[role="textbox"]')
textbox.send_keys('Hello World!I am Robot~ ^_^')
print('輸入文字')
sleep(1)
imgInput = driver.find_element(By.CSS_SELECTOR, 'input[data-testid="fileInput"]')
imgInput.send_keys('/Users/oxxo/Desktop/oxxo.png')
print('上傳圖片')
sleep(1)
buttons = driver.find_elements(By.CSS_SELECTOR, 'div[role="button"]')
for i in buttons:
if i.text == '推文' or i.text == 'Tweet':
i.click()
print('推文完成')
break
sleep(1)
driver.close()
微信扫码关注
抖音扫码关注