51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 2814|回复: 2
打印 上一主题 下一主题

Python抓取网页动态数据——selenium webdriver的使用

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2018-6-14 16:19:09 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
1. 文章目的

当我们使用Python爬取网页数据时,往往用的是urllib模块,通过调用urllib模块的urlopen(url)方法返回网
页对象,并使用read()方法获得url的html内容,然后使用BeautifulSoup抓取某个标签内容,结合正则表
达式过滤。但是,用urllib.urlopen(url).read()获取的只是网页的静态html内容,很多动态数据(比如网站
访问人数、当前在线人数、微博的点赞数等等)是不包含在静态html里面的,例如我要抓取这个bbs网
站中点击打开链接 各个板块的当前在线人数,静态html网页是不包含的(不信你查看页面源代码试试,
只有简单的一行)。像这些动态数据更多的是由JavaScript、JQuery、PHP等语言动态生成的,因此再
用抓取静态html内容的方式就不合适了。

2. 解决思路

我尝试过网上所说的用浏览器自带的开发者工具(一般是F12弹出相应网页的开发者工具),查看网络
可以获得动态数据的走向,但这需要从众多的url中找出蛛丝马迹,个人觉得太麻烦了。另外,用查看器
查看的html内容也是包含动态数据的,但这有几个问题:怎么实时获取查看器的html内容?怎么将查看
器的html导入python程序?因此利用查看器的html内容的方法也是不符合抓取程序要求的。

而偶然间发现了selenium模块,发现这个模块可以很方便地根据url加载页面获得session,并找到当前se
ssion的相应标签。本文将通过selenium webdriver模块的使用,以获取这些动态生成的内容,尤其是一
些重要的动态数据。其实selenium模块的功能不是仅仅限于抓取网页,它是网络自动化测试的常用模块
,在Ruby、Java里面都有广泛使用,Python里面虽然使用相对较少,但也是一个非常简洁高效容易上
手的自动化测试模块。通过利用selenium的子模块webdriver的使用,解决抓取动态数据的问题,还可以
可以对selenium有基本认识,为进一步学习自动化测试打下基础。

3. 实现过程

3.1 运行环境

我是在windows 7系统上安装了Python 2.7版本,使用Python(X,Y)这个IDE,安装好的Python库没有自
带selenium,在Python程序中直接import selenium会提示没有这个模块,联网状态下cmd直接输入pip i
nstall selenium,系统会找到Python的安装目录直接下载解压并安装这个模块。等到终端提示完成后可
以看看,在C:\Python27\Lib\site-packages目录下有没有selenium模块,这个目录取决于你安装Python
的路径。如果有selenium和selenium-2.47.3.dist-info这两个文件夹,代表模块可以在Python程序中被加
载了。
使用webdriver抓取动态数据

先导入webdriver子模块
from selenium import webdriver
获得浏览器的session,浏览器用Firefox、Chrome、IE等都可以,这里以Firefox为例
browser = webdriver.Firefox()
加载页面,url自己指定一个合法的字符串即可
browser.get(url)
获得了session对象后,要定位元素,webdriver提供了一系列的元素定位方法,常用的有以下几种方式:
id
name
class-name
link
text
partial
link
text
tag
name
xpath
cssselector
比如通过id定位,返回所有元素组成的list,lis=borwser.find_elements_by_id_name('kw'')
通过class-name定位,lis=find_elements_by_class_name('title_1')
更详细的定位方式可以参考selenium webdriver(python)教程的第三章-定位方式部分(第一版可在百
度文库阅览)
结合正则表达式过滤相关信息
定位后的元素有些是不想要的,用正则过滤掉即可,比如我想只提取英文字符(包括0-9),建立下面
的正则
pa=re.compile(r'\w+')
for u in lis:
en=pa.findall(u.lis)
print en
关闭会话
当执行完抓取操作后,必须关闭session,不然让它一直占内存会影响机器其他进程的运行
browser.close()或者browser.quit()都可以关闭session,前者只是关闭当前的session,浏览器的webdrive
r不关闭,后者则是包括webdriver这些东西全部shut down
加入异常处理
这是有必要的,因为有时会获得session失败,因此要把上述语句块放入try里面,然后exception处理异常
except NoSuchElementException:
assert 0, "can't find element"
4. 代码实现

我抓取了点击打开链接 指定分区中各个板块的在线人数,指定分区id号(0-9),可以获得板块名称和对
应的在线人数,形成列表打印出来,代码如下

[python] view plain

# -*- coding: utf-8 -*-  

from selenium import webdriver  
from selenium.common.exceptions import NoSuchElementException  
import time  
import re  

def find_sec(secid):  
    pa=re.compile(r'\w+')  
    browser = webdriver.Firefox() # Get local session of firefox  
    browser.get("http://bbs.byr.cn/#!section/%s "%secid) # Load page  
    time.sleep(1) # Let the page load  
    result=[]  
    try:  
        #获得版面名称和在线人数,形成列表  
        board=browser.find_elements_by_class_name('title_1')  
        ol_num=browser.find_elements_by_class_name('title_4')  
        max_bindex=len(board)  
        max_oindex=len(ol_num)  
        assert max_bindex==max_oindex,'index not equivalent!'  

        #版面名称有中英文,因此用正则过滤只剩英文的  
        for i in range(1,max_oindex):  
            board_en=pa.findall(board.text)  
            result.append([str(board_en[-1]),int(ol_num.text)])  

        browser.close()  
        return result  
        except NoSuchElementException:  
            assert 0, "can't find element"  


print find_sec('5')  #打印分区5下面的所有板块的当前在线人数列表
运行结果如下:

终端打印效果
4. 总结

无论是从代码简洁度还是执行效率上看,selenium都非常优秀,用selenium webdriver抓取动态数据非
常简洁高效,进一步地利用这个实现数据挖掘、机器学习等深层研究也是可以的,因此selenium+pyth
on是很值得深入学习的!如果觉得用selenium每次打开浏览器很不方便,可以用phantomjs模拟一个虚
拟浏览器出来,在这里就不做赘述了。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

x
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1
回复

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-11-26 23:50 , Processed in 0.064996 second(s), 26 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表