前一篇实作了 Selenium 爬取 Dcard 文章的爬虫,可以看到会出现一个浏览器视窗模拟使用者,并使用内建的选择器锁定文章资讯。
首先,Dcard 的设计是不会一次将所有文章皆读取完成,而是每次使用者卷动到底部时读取新的文章,因此如果要写爬取 Dcard 的爬虫(不使用 Dcard API)需要模拟使用者卷动萤幕。
今天要带各位加上的功能是模拟使用者滚动萤幕,当爬取完成目前的所有内容後,自动滚动萤幕到最底部,之後再进行爬取,以此达到取得 Dcard 上文章的目的。
首先,我们先实作使用者输入卷动次数的程序,并完成初步 Selenium 程序。
from selenium import webdriver
from time import sleep
import json
if __name__ == '__main__':
scroll_time = int(input('请输入想要卷动几次'))
driver = webdriver.Chrome()
driver.get('https://www.dcard.tw/f')
接下来,我们要完成程序卷动的部分。
在 Selenium 中支援执行 JavaScript 的功能,因此我们能透过 JavaScript 的 window.scrollTo
来达到卷动萤幕的效果。
from selenium import webdriver
from time import sleep
import json
if __name__ == '__main__':
scroll_time = int(input('请输入想要卷动几次'))
driver = webdriver.Chrome()
driver.get('https://www.dcard.tw/f')
sleep(2)
js = "window.scrollTo(0, document.body.scrollHeight);"
driver.execute_script(js)
完成卷动萤幕後,我们写一个 for-loop 执行使用者输入的次数。
from selenium import webdriver
from time import sleep
import json
if __name__ == '__main__':
scroll_time = int(input('请输入想要卷动几次'))
driver = webdriver.Chrome()
driver.get('https://www.dcard.tw/f')
for now_time in range(1, scroll_time+1):
sleep(2)
print(f"now scroll {now_time}/{scroll_time}")
js = "window.scrollTo(0, document.body.scrollHeight);"
driver.execute_script(js)
接下来,我们能将昨天实作的文章爬取写入到回圈当中。
有时会遇到无法找寻到元素的问题(文章删除或广告),因此我们能在爬取文章资讯的回圈中加个 try-except,来让程序不会因此停止。
from selenium import webdriver
from time import sleep
import json
if __name__ == '__main__':
scroll_time = int(input('请输入想要卷动几次'))
driver = webdriver.Chrome()
driver.get('https://www.dcard.tw/f')
results = []
for now_time in range(1, scroll_time+1):
sleep(2)
eles = driver.find_elements_by_class_name('tgn9uw-0')
for ele in eles:
try:
title = ele.find_element_by_class_name('tgn9uw-3').text
href = ele.find_element_by_class_name(
'tgn9uw-3').get_attribute('href')
subtitle = ele.find_element_by_class_name('tgn9uw-4').text
result = {
'title': title,
'href': href,
'subtitle': subtitle
}
results.append(result)
except:
pass
print(f"now scroll {now_time}/{scroll_time}")
js = "window.scrollTo(0, document.body.scrollHeight);"
driver.execute_script(js)
with open('Dcard-articles.json', 'w', encoding='utf-8') as f:
json.dump(results, f, indent=2,
sort_keys=True, ensure_ascii=False)
driver.quit()
这样会有一个明显的问题,会导致有些文章会重复爬取,如下图。
解决这个问题也非常容易,只要记录上一次爬取的最後一个文章元素,之後下次爬取时将那个元素之前的元素删除即可(或者只进行爬取那个元素之後的元素)
from selenium import webdriver
from time import sleep
import json
if __name__ == '__main__':
scroll_time = int(input('请输入想要卷动几次'))
driver = webdriver.Chrome()
driver.get('https://www.dcard.tw/f')
results = []
prev_ele = None
for now_time in range(1, scroll_time+1):
sleep(2)
eles = driver.find_elements_by_class_name('tgn9uw-0')
# 若串列中存在上一次的最後一个元素,则撷取上一次的最後一个元素到当前最後一个元素进行爬取
try:
# print(eles)
# print(prev_ele)
eles = eles[eles.index(prev_ele):]
except:
pass
for ele in eles:
try:
title = ele.find_element_by_class_name('tgn9uw-3').text
href = ele.find_element_by_class_name(
'tgn9uw-3').get_attribute('href')
subtitle = ele.find_element_by_class_name('tgn9uw-4').text
result = {
'title': title,
'href': href,
'subtitle': subtitle
}
results.append(result)
except:
pass
prev_ele = eles[-1]
print(f"now scroll {now_time}/{scroll_time}")
js = "window.scrollTo(0, document.body.scrollHeight);"
driver.execute_script(js)
with open('Dcard-articles.json', 'w', encoding='utf-8') as f:
json.dump(results, f, indent=2,
sort_keys=True, ensure_ascii=False)
driver.quit()
到目前为止,功能已完成。
今天达成了在 Selenium 中执行 JavaScript 语句达成卷动萤幕的效果,并透过撷取串列达到不重复爬取的效果。
明天会带各位实战 Instagram 上自动点击好友贴文赞的爬虫。
Dcard : https://www.dcard.tw/f
Selenium with Python docs : https://selenium-python.readthedocs.io/
Selenium docs : https://readthedocs.org/projects/selenium-python/downloads/pdf/latest/
<<: 大共享时代系列_019_水电、装潢、建筑工程交流与媒合
>>: 你是谁、你的过去都不重要,成功的能力永远都从你开始。
p段落标签最常使用搭配段落文章使用 同时也是一个display:block特性的元素 <p&g...
接着来讲讲常用的物件导向一些基本概念.... 封装 可能你知道套件函式名称,但不知道里面是什麽就叫封...
为什麽我们需要 SWR ? 先前我们已经了解了 CSR、SSR 与 SSG 的优劣,SSR 与 SS...
以前遇到一个情况阿,使用者输入,我要ㄧ个汉堡,二杯奶茶,到後台却变成,我要\xe3\x84\xa7个...
Day15 在 Space Invaders 的游戏设计中, 除了随着不断前进而产生的压迫感之外, ...