zoukankan      html  css  js  c++  java
  • Python抓取网页动态数据——selenium webdriver的使用

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

    解决思路
    我尝试过网上所说的用浏览器自带的开发者工具(一般是F12弹出相应网页的开发者工具),查看网络可以获得动态数据的走向,但这需要从众多的url中找出蛛丝马迹,个人觉得太麻烦了。另外,用查看器查看的html内容也是包含动态数据的,但这有几个问题:怎么实时获取查看器的html内容?怎么将查看器的html导入python程序?因此利用查看器的html内容的方法也是不符合抓取程序要求的。
    而偶然间发现了selenium模块,发现这个模块可以很方便地根据url加载页面获得session,并找到当前session的相应标签。本文将通过selenium webdriver模块的使用,以获取这些动态生成的内容,尤其是一些重要的动态数据。其实selenium模块的功能不是仅仅限于抓取网页,它是网络自动化测试的常用模块,在Ruby、Java里面都有广泛使用,Python里面虽然使用相对较少,但也是一个非常简洁高效容易上手的自动化测试模块。通过利用selenium的子模块webdriver的使用,解决抓取动态数据的问题,还可以可以对selenium有基本认识,为进一步学习自动化测试打下基础。

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

    使用webdriver抓取动态数据
    1.先导入webdriver子模块

    from selenium import webdriver

    2.获得浏览器的session,浏览器用Firefox、Chrome、IE等都可以,这里以Firefox为例

    browser = webdriver.Firefox()

    3.加载页面,url自己指定一个合法的字符串即可

    browser.get(url)

    4.获得了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)教程的第三章-定位方式部分(第一版可在百度文库阅览,第二版开始就收费了>-<)

    5.结合正则表达式过滤相关信息

    定位后的元素有些是不想要的,用正则过滤掉即可,比如我想只提取英文字符(包括0-9),建立下面的正则

    pa=re.compile(r'w+')

    for u in lis:

    en=pa.findall(u.lis)

    print en
    6.关闭会话

    当执行完抓取操作后,必须关闭session,不然让它一直占内存会影响机器其他进程的运行

    browser.close()或者browser.quit()都可以关闭session,前者只是关闭当前的session,浏览器的webdriver不关闭,后者则是包括webdriver这些东西全部shut down

    7.加入异常处理

    这是有必要的,因为有时会获得session失败,因此要把上述语句块放入try里面,然后exception处理异常

    except NoSuchElementException:

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

    -- 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[i].text)
        result.append([str(board_en[-1]),int(ol_num[i].text)])
        
    browser.close()
    return result
    

    except NoSuchElementException:
    assert 0, "can't find element"
    打印分区5下面的所有板块的当前在线人数列表
    print find_sec('5')

    运行结果如下:

  • 相关阅读:
    基本技能训练之线程
    关于UEditor的使用配置(图片上传配置)
    PAT 乙级练习题1002. 写出这个数 (20)
    codeforces 682C Alyona and the Tree DFS
    codeforces 681D Gifts by the List dfs+构造
    codeforces 678E Another Sith Tournament 概率dp
    codeforces 680E Bear and Square Grid 巧妙暴力
    codeforces 678D Iterated Linear Function 矩阵快速幂
    codeforces 679A Bear and Prime 100 交互
    XTUOJ 1248 TC or CF 搜索
  • 原文地址:https://www.cnblogs.com/wang1018-kuiying/p/14462206.html
Copyright © 2011-2022 走看看