Selenium元素定位初探(以今日头条首页为例)

版权声明:原创文章,未经允许不得转载。www.data-insights.cn | www.data-insight.cn | https://blog.csdn.net/qixizhuang/article/details/84554242

随着网页技术的发展,动态网页的比例越来越高,原来抓取静态网页的许多方法变得不再适用;再加上越来越多的网站添加了各种复杂的反爬虫策略,导致直接通过网络请求的方式去抓取页面的方式已经有些落伍了。

而Selenium可以通过模拟浏览器的真实行为来访问网页并将页面源码缓存下来,从而实现所见即所得的效果。Selenium本身广泛应用于测试领域,但是它所见即所得的特性基本上满足了我们抓取绝大多数页面的需求,因此今天我们就看一下如何通过Selenium访问页面并通过不同的方式定位到我们需要的元素,从而完成页面抓取。

我们以今日头条的官网首页(https://www.toutiao.com)来进行演示。


欢迎大家关注我的个人博客【数洞】 【备用站】

一、通过ID定位

首先我们看下如何通过元素id来定位。在头条首页,有一个右边栏,通过检查页面元素我们发现,这是一个id="rightModule"<div>标签,那么我们就通过这个ID来定位到这个元素,并且打印出该元素的class属性。

# -*- coding:utf-8 -*-
from selenium import webdriver

if __name__ == '__main__':
    driver = webdriver.Chrome()
    driver.get('https://www.toutiao.com')
    element_class = driver.find_element_by_id('rightModule').get_attribute('class')
    print(element_class)

输出为:

bui-right index-right-bar

在这里,我们先通过driver = webdriver.Chrome()启动一个Chrome Driver,这里需要保证我们的环境变量目录中已经包含了与我们的Chrome浏览器版本对应的chromedriver,大家可以自行搜索下载并安装。

然后我们通过driver.get('https://www.toutiao.com'来控制浏览器打开头条的首页;接下来,find_element_by_id('rightModule')的作用就是在页面源码中定位到包含了id="rightModule"属性的元素,也就是上边提到的右边栏对应的元素;最后我们使用get_attribute('class')方法,取出该元素class属性的值。

很简单,不是吗?

另外提一句,所有的find_element_by_XXX方法都会返回定位到的第一个元素,加个s后,即所有的find_elements_by_XXX方法则会以列表形式返回符合条件的所有元素。比如上边这个例子,如果我们改成driver.find_elements_by_id('rightModule')则会以列表形式返回所有符合条件的元素(当然,在这个例子中,事实上列表的长度也只有1)。

二、通过name定位

ID类似,selenium提供了find_element_by_namefind_elements_by_name方法来通过name属性定位元素。

头条首页右侧,有一个淘宝广告的模块,里边有一些轮播图,接下来我们就通过name属性定位到它,并打印出它的ad_name属性的值。

element_ad_name = driver.find_element_by_name('home_right*top_1')\
                      .get_attribute('ad_name')
print(element_ad_name)

输出为:

h_300*250_TB_314

使用方法和find_element_by_id如出一辙。

三、通过class定位

聪明如你可能会猜测,通过class定位元素的方法应该是find_element_by_classfind_elements_by_class,那么,“恭喜你,答错了!”(这一句是我上学的时候最痛恨的被老师嘲讽的话,今天说出来给别人,感觉很爽!)

事实上,这两个方法应该是find_element_by_class_namefind_elements_by_class_name,比我们猜测的多了个后缀(是的,最开始我也猜错了),他们会定位到class取值包含某个字符串的所有元素。

我们注意到头条首页左侧有一个边栏,列出了一些频道,那么我们如何定位并打印出这些频道名称呢?

观察页面源码,我们发现频道名称隐藏在一个<span>标签中,而这个<span>标签,有一个class="channel-item"<a>父标签。同时我们也注意到,第一个频道——“推荐”的标签属性与其他的频道标签属性不同,它的class取值为channel-item active

channel_element_list = driver.find_elements_by_class_name('channel-item')
channel_list = [x.text for x in channel_element_list]
print(channel_list)

输出为:

['推荐', '阳光宽频', '热点', '图片', '科技', '娱乐', '游戏', '体育', '汽车', '财经', '搞笑', '更多', '', '', '', '', '', '', '', '', '', '', '']

我们看到除了页面上看到的频道以外,还有一些空的字符串。这是因为“更多”这里在悬浮的时候会产生更多的可选频道,我们在没有进行悬浮操作的时候,暂时看不到这些频道。这个问题以后我们可以通过一系列的动作等方式来解决。

四、通过tag名称定位

通过标签名称定位的方法为find_element_by_tag_namefind_elements_by_tag_name,这个方法可以直接选择标签。

仍以上例来说明,我们看到,上边的例子中,我们直接对选择到的<a>标签选择了它的text属性,并获取了文本,但事实上文本存在于<a>的子标签<span>中。那么我们为什么能成功呢?这是因为.text属性查询的是所有子孙节点中的文本。

考虑另一种情况,假如上述的<a>标签有多个子孙标签,且都有不同的文本,而我们只要想<span>标签中的文本时,应该如何操作?

text = driver.find_elements_by_class_name('channel-item')[5].find_element_by_tag_name('span').text
print(text)

输出为:

'娱乐'

可以看到,我们在定位到<a>标签后,选择了它的子标签<span>并成功打印出对应的文本。

五、通过XPath定位

这是一大利器,XPath在定位页面元素上的强大不容置疑,不了解XPath的同学可以阅读我的另一篇文章:《Python3使用Xpath解析网易云音乐歌手页面》。这篇文章通过实战演练,讲解了如何快速上手XPath并解析网易云音乐的歌手页面。

selenium中提供了对XPath的支持,我们可以通过find_element_by_xpathfind_elements_by_xpath来灵活地运用XPath进行元素定位。

头条首页中间,有一些内容列表,那我们就看看如何获取这些内容的标题。

观察页面源码,可以看到这些内容都藏在一个class="title-box"<div>标签的子标签<a>中。

title_elements = driver.find_elements_by_xpath('//div[@class="title-box"]/a')
titles = [x.text for x in title_elements]
print(titles)

输出为(输出较长,故隐藏部分内容):

['中共中央政治局召开会议 习近平主持', '五次出席G20峰会,习近平提出哪些“中国主张”?', ...]

事实上,XPath是支持直接获取文本列表的,但是目前seleniumXPath的支持还不够丰富。想要体验更强大的XPath的朋友可以读一下上边提到的那篇文章,十分钟即可入门。

其他定位方式

目前selenium支持的元素定位方式还有三种:

  • CSS选择器:find_element_by_css_selectorfind_elements_by_css_selector,支持以层叠样式表(CSS)的方式定位元素;
  • Link:find_element_by_link_textfind_elements_by_link_text,支持通过链接文本来定位元素;
  • Partial Link:find_element_by_partial_link_textfind_elements_by_partial_link_text,支持通过链接文本的一部分来定位元素。

不过这三种我自己用的比较少,它们的使用也非常简单,有CSS基础或者对这三种方法感兴趣的朋友可以自行检索资料学习。事实上,上述的五种方法已经足够我们选取任何页面元素了。

猜你喜欢

转载自blog.csdn.net/qixizhuang/article/details/84554242