基于今日头条的实战[稍微复杂]
- 通过Selenium访问百度热词
- 通过Selenium搜索相关热词
- 获取第一条结果
- 定位元素—— 抓取内容
- 存储数据
通过Selenium访问百度热词
我们的目标网站为百度搜索风云榜。先打开百度搜索风云榜网站观察一下,我们的
为了获取元素,首先要进行元素定位。在网页中按F12键打开开发者工具,对实时热点这几条消息进行定位,右击并获取XPath。然后读者就会惊讶的发现,它的XPath都很类似,不同的只是中间一个叫作li的标签名。这就意味着,我们只需要更改li标签对应的数字,就可以完成对所有XPath的定位。
//[@id=“hot-list”]/li[1]/a[1]
//[@id=“hot-list”]/li[2]/a[1]
//*[@id=“hot-list”]/li[3]/a[1]
这些热词都在一个ul下面。在ul列表中,因为所有元素都是采用li标签进行并列排序的,所以它们的标签其实也很相像,主要的区别就是li标签的序号。
# 导入库
from selenium import webdriver
# 启动浏览器,并打开百度热搜榜
driver = webdriver.Firefox()
driver.get("http://top.baidu.com/")
driver.implicitly_wait(20) # 加个隐式等待,最长等待时间20秒
# 整合拼接Xpath,因为之前获取的每个热搜的只是li[],[]中的不一样,是有顺序的,故可以做for操作
for i in range(10):
xpath = '//*[@id="hot-list"]/li['+str(i+1)+']/a[1]'
print(driver.find_element_by_xpath(xpath).get_attribute('title'))
# 退出
driver.quit()
通过Selenium搜索相关热词
刚才我们输出了获取的关键词,如果我们要调用这些内容,就不能再输出了。我们考虑将获取的内容保存在字典中。具体代码如下。
# 导入库
from selenium import webdriver
import time
# 启动浏览器,并打开百度热搜榜
driver = webdriver.Firefox()
driver.get("http://top.baidu.com/")
driver.implicitly_wait(20) # 加个隐式等待,最长等待时间20秒
getValue = []
# 整合拼接Xpath,因为之前获取的每个热搜的只是li[],[]中的不一样,是有顺序的,故可以做for操作
for i in range(10):
xpath = '//*[@id="hot-list"]/li['+str(i+1)+']/a[1]'
value= driver.find_element_by_xpath(xpath).get_attribute('title')
getValue.append(value)
# 获取列表中的第一个元素
keyword = getValue[0]
# 去今日头条搜索第一个元素
URL='https://www.toutiao.com/search/?keyword=%s' %keyword
driver.get(URL)
time.sleep(2)
退出
driver.quit()
获取第一条结果
在搜索结束以后,我们使用代码模拟用户的操作—— 单击搜索后页面中的第一条结果。与刚才一样,定位元素,我们先看一下第一条结果能否触发单击操作的最下一层标签(这里选择的是文字内容)。具体代码如下。
然后我们通过开发者工具,获取它的XPath,代码如下。
//*[@id=“J_section_0”]/div/div/div/div/div[1]/a/span
学到这里,相信读者已经能够轻松地写出定位元素和模拟单击操作的代码。
但有一个问题值得我们考虑:如果按照我们刚才讲述的步骤继续进行操作,我们再运行几次后会发现经常会有出错的情况,这是因为什么呢?因为程序运行的速度太快,网页更新跟不上,程序在定位第一个元素的时候,网页通常尚未加载完,因此程序就会报错,等网页加载完了,程序已经退出了。考虑到今日头条加载的内容较多,为了提高程序运行的效率以及准确率,我们使用在之前文章中介绍过的显式等待方法。
# 导入库
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.common.by import By
import time
# 启动浏览器,并打开百度热搜榜
driver = webdriver.Chrome()
driver.get("http://top.baidu.com/")
driver.implicitly_wait(20) # 加个隐式等待,最长等待时间20秒
getValue = []
# 整合拼接Xpath,因为之前获取的每个热搜的只是li[],[]中的不一样,是有顺序的,故可以做for操作
for i in range(10):
xpath = '//*[@id="hot-list"]/li['+str(i+1)+']/a[1]'
value= driver.find_element_by_xpath(xpath).get_attribute('title')
getValue.append(value)
# 获取列表中的第一个元素
keyword = getValue[0]
# 去今日头条搜索第一个元素
URL='https://www.toutiao.com/search/?keyword=%s' %keyword
driver.get(URL)
# XPath拼接
XPath = '//*[@id="J_section_0"]/div/div/div/div/div[1]/a/span'
# 调用显式等待
try:
WebDriverWait(driver, 20, 0.5).until(expected_conditions.presence_of_element_located((By.XPATH, XPath)))
finally:
driver.find_element_by_xpath(XPath).click()
定位元素—— 抓取内容
打开页面,获取页面的内容,并再次查看title所在的标签。
查看发布者和时间所在的标签。
查看内容所在的标签。
# 导入库
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.common.by import By
import time
# 定义函数
def getInfo():
publisher = driver.find_element_by_xpath('/html/body/header/span')
title = driver.find_element_by_xpath('/html/body/header/h1')
text = driver.find_element_by_xpath('html/body/article')
item = [publisher.text, title.text, text.text]
return item
# 启动浏览器,并打开百度热搜榜
driver = webdriver.Chrome()
driver.get("http://top.baidu.com/")
driver.implicitly_wait(20) # 加个隐式等待,最长等待时间20秒
getValue = []
# 整合拼接Xpath,因为之前获取的每个热搜的只是li[],[]中的不一样,是有顺序的,故可以做for操作
for i in range(10):
xpath = '//*[@id="hot-list"]/li['+str(i+1)+']/a[1]'
value= driver.find_element_by_xpath(xpath).get_attribute('title')
getValue.append(value)
# 获取列表中的第一个元素
keyword = getValue[0]
# 去今日头条搜索第一个元素
URL='https://www.toutiao.com/search/?keyword=%s' %keyword
driver.get(URL)
# XPath拼接
XPath = '//*[@id="J_section_0"]/div/div/div/div/div[1]/a/span'
# 调用显式等待
try:
WebDriverWait(driver, 20, 0.5).until(expected_conditions.presence_of_element_located((By.XPATH, XPath)))
finally:
driver.find_element_by_xpath(XPath).click()
# 给页面留足加载时间,同时也为了防止IP地址被禁
time.sleep(1)
# 获取所有句柄
all_handles = driver.window_handles
# 跳转到最后一个句柄,也就是刚刚打开的页面
driver.switch_to.window(all_handles[-1])
# 获取信息
info=getInfo()
print(info)
执行结果
存储数据
写的程序已经比较成熟了,但当我们需要分析大规模的数据时,这样输出的数据明显是不行的,我们需要将数据按照统一的格式进行存储。我们将文件以CSV格式存储,CSV格式的文件将会在后续讲解。
在开始存储数据之前,我们还需要考虑到一件事情。今日头条上关于最热新闻的报道肯定有很多,不是一页就能加载完的,因此我们还需要写入一个能够模拟下拉的方法,来为我们加载排名靠后的内容。让人愉快的是,Selenium已经为我们提供了模拟键鼠(即键盘和鼠标)操作的方法。可以从ActionChains库中调用模拟键鼠操作的方法。
ActionChains库包含的关于鼠标的操作方法如下。
●’click(on_element=None)’,表示单击。
●’click_and_hold(on_element=None)’,表示按住鼠标左键后不松开。●’context_click(on_element=None)’,表示右击。●’double_click(on_element=None)’,表示双击。
●’drag_and_drop(source, target)’,表示拖动到某个元素。●’drag_and_drop_by_offset(source, xoffset, yoffset)’,表示拖动到某个坐标后松开。
●’release(on_element=None) ',表示释放鼠标左键。
●’move_by_offset(xoffset, yoffset) ',表示鼠标指针移动到某个坐标。●’move_to_element(to_element) ',表示鼠标指针移动到某个元素。●’move_to_element_with_offset(to_element, xoffset, yoffset) ',表示鼠标指针移动到距某元素左上方指定的位置。
ActionChains库包含的关于键盘操作的方法如下。
●’key_down(value, element=None) ',表示按某个键盘上的键。
●’key_up(value, element=None) ',表示松开某个键。
●’send_keys(*args) ‘,表示发送。
●’perform()’,表示执行已经添加到生成器中的操作。
代码省略~