Selenium自動化|輕松爬取公眾號文章

下面就來詳細(xì)講解如何一步步操作,文末附完整代碼。
Selenium介紹
Selenium是一個(gè)用于web應(yīng)用程序自動化測試的工具,直接運(yùn)行在瀏覽器當(dāng)中,可以通過代碼控制與頁面上元素進(jìn)行交互,并獲取對應(yīng)的信息。Selenium很大的一個(gè)優(yōu)點(diǎn)是:不需要復(fù)雜地構(gòu)造請求,訪問參數(shù)跟使用瀏覽器的正常用戶一模一樣,訪問行為也相對更像正常用戶,不容易被反爬蟲策略命中,所見即所得。而且在抓取的過程中,必要時(shí)還可人工干預(yù)(比如登錄、輸入驗(yàn)證碼等)。
Selenium常常是面對一個(gè)嚴(yán)格反爬網(wǎng)站無從入手時(shí)的保留武器。當(dāng)然也有缺點(diǎn):操作均需要等待頁面加載完畢后才可以繼續(xù)進(jìn)行,所以速度要慢,效率不高(某些情況下使用headless和無圖模式會提高一點(diǎn)效率)。
需求分析和代碼實(shí)現(xiàn)
from?selenium?import?webdriver
from?selenium.webdriver.common.by?import?By
from?selenium.webdriver.support?import?expected_conditions?as?EC
from?selenium.webdriver.support.wait?import?WebDriverWait
#?導(dǎo)入第2-4行是為了馬上會提到的?顯式等待
import?time
import?datetime
driver?=?webdriver.Chrome()
driver.get('https://weixin.sogou.com/')
wait?=?WebDriverWait(driver,?10)
input?=?wait.until(EC.presence_of_element_located((By.NAME,?'query')))
input.send_keys('早起Python')
driver.find_element_by_xpath("http://input[@class='swz']").click()driver.implicitly_wait(10),顯示等待明確了等待條件,只有該條件觸發(fā),才執(zhí)行后續(xù)代碼,如這里我用到的代碼,當(dāng)然也可以用time模塊之間設(shè)定睡眠時(shí)間,睡完了再運(yùn)行后續(xù)代碼。
另外只能獲取前10頁100條的結(jié)果,查看后續(xù)頁面需要微信掃碼登錄:

因此從這里開始,代碼的執(zhí)行邏輯為:
先遍歷前10頁100個(gè)文章的作者名字,如果不是“早起Python”則跳過,是則獲取對應(yīng)的標(biāo)題名字、發(fā)布日期和鏈接
第10頁遍歷完成后自動點(diǎn)擊登錄,此時(shí)需要人工介入,掃碼完成登錄
代碼檢測登錄是否完成(可以簡化為識別“下一頁”按鈕是否出現(xiàn)),如果登錄完成則繼續(xù)從11頁遍歷到最后一頁(沒有“下一頁”按鈕)
由于涉及兩次遍歷則可以將解析信息包裝成函數(shù):
num?=?0
def?get_news():
????global?num?#?放全局變量是為了給符合條件的文章記序
????time.sleep(1)
????news_lst?=?driver.find_elements_by_xpath("http://li[contains(@id,'sogou_vr_11002601_box')]")
????for?news?in?news_lst:
????????#?獲取公眾號來源
????????source?=?news.find_elements_by_xpath('div[2]/div/a')[0].text
????????if?'早起'?not?in?source:
????????????continue
????????num?+=?1
????????#?獲取文章標(biāo)題
????????title?=?news.find_elements_by_xpath('div[2]/h3/a')[0].text
????????#?獲取文章發(fā)表日期
????????date?=?news.find_elements_by_xpath('div[2]/div/span')[0].text
????????#?文章發(fā)表的日期如果較近可能會顯示“1天前”?“12小時(shí)前”?“30分鐘前”
????????#?這里可以用`datetime`模塊根據(jù)時(shí)間差求出具體時(shí)間
????????#?然后解析為`YYYY-MM-DD`格式
????????if?'前'?in?date:
????????????today?=?datetime.datetime.today()
????????????if?'天'?in?date:
????????????????delta?=?datetime.timedelta(days=int(date[0]))
????????????elif?'小時(shí)'?in?date:
????????????????delta?=?datetime.timedelta(hours=int(date.replace('小時(shí)前',?'?')))
????????????else:
????????????????delta?=?datetime.timedelta(minutes=int(date.replace('分鐘前',?'?')))
????????????date?=?str((today?-?delta).strftime('%Y-%m-%d'))
????????date?=?datetime.datetime.strptime(date,?'%Y-%m-%d').strftime('%Y-%m-%d')
????????#?獲取url
????????url?=?news.find_elements_by_xpath('div[2]/h3/a')[0].get_attribute('href')
????????print(num,?title,?date)
????????print(url)
????????print('-'?*?10)
for?i?in?range(10):
????get_news()
????if?i?==?9:
????????#?如果遍歷到第十頁則跳出循環(huán)不需要點(diǎn)擊“下一頁”
????????break
????driver.find_element_by_id("sogou_next").click()接下來就是點(diǎn)擊“登錄”,然后人工完成掃碼,可以利用while True檢測登錄是否成功,是否出現(xiàn)了下一頁按鈕,如果出現(xiàn)則跳出循環(huán),點(diǎn)擊“下一頁”按鈕并繼續(xù)后面的代碼,否則睡3秒后重復(fù)檢測:
driver.find_element_by_name('top_login').click()
while?True:
????try:
????????next_page?=?driver.find_element_by_id("sogou_next")
????????break
????except:
????????time.sleep(3)
next_page.click()效果如圖:

然后就是重新遍歷文章了,由于不知道最后一頁是第幾頁可以使用while循環(huán)反復(fù)調(diào)用解析頁面的函數(shù)半點(diǎn)擊“下一頁”,如果不存在下一頁則結(jié)束循環(huán):
while?True:
????get_news()
????try:
????????driver.find_element_by_id("sogou_next").click()
????except:
????????break
#?最后退出瀏覽器即可
driver.quit()是不是少了點(diǎn)什么?對,就是數(shù)據(jù)存儲,在爬下來數(shù)據(jù)之后和之前一樣利用openpyxl存儲到excel中即可(如果不想用此模塊的話也可以改用 csv 或者 pandas 保存表格文件):

作者:陳熹
來源:早起Python
_往期文章推薦_
