小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

栏目: Python · 发布时间: 8年前

内容简介:小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

引言

自从学习了爬虫之后,每天不写个小爬虫爬爬小姐姐,都觉得浑身难受:

小猪的 <a href='https://www.codercto.com/topics/20097.html'>Python</a> 学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

小姐姐是挺好看的,只是身体日渐消瘦而已, 多喝营养快线 就好!

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

(快来学Python爬虫,一起爬可爱的小姐姐啊~)

抓多了发现有一些小网站很 狡猾 ,竟然搞起 反爬虫 来了,不直接 生成数据,而是通过 加载JS来生成数据 ,然后你打开Chrome浏览器的 开发者选项 ,然后你会发现 Elements页面结构和Network抓包 抓包 返回的内容竟然是不一样的,Network抓包那里竟然 没有对应的数据 , 本该是数据的地方,竟然是 JS代码 ,比如煎蛋的妹子图:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

对于我这种不会JS的安卓狗来说,不禁感叹:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

抓不到数据怎么破,开始我还想着自学一波JS基本语法,再去模拟抓包 拿到别人的JS文件,自己再去分析逻辑,然后捣鼓出真正的URL,后来 还是放弃了,有些JS竟然他么的是加密的,而且要抓的页面那么多, 每个这样分析分析到什么时候...

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

后面意外发现有个 自动化测试框架Selenium 可以帮我们处理这个问题。 简单说下这个东西有什么用吧,我们可以 编写代码让浏览器

  • 1.自动加载网页;
  • 2.模拟表单提交(比如模拟登录),获取需要的数据;
  • 3.页面截屏;
  • 4.判断网页某些动作是否发生,等等。

然后这个东西是 不支持浏览器功能 的,你需要和 第三方的浏览器 一起搭配使用,支持下述浏览器,需要把对应的浏览器驱动下载 到Python的对应路径下:

Chrome: sites.google.com/a/chromium.… FireFoxgithub.com/mozilla/gec… PhantomJSphantomjs.org/ IEselenium-release.storage.googleapis.com/index.html Edgedeveloper.microsoft.com/en-us/micro… Operagithub.com/operasoftwa…

直接开始本节的内容吧~

1.安装Selenium

这个就很简单了,直接通过pip命令行进行安装:

sudo pip install selenium

PS:想起之前公司小伙伴问过我pip在win上怎么执行不了,又另外下了很多pip, 其实如果你安装了Python3的话,已经默认带有pip了,你需要另外配置下环境 变量,pip的路径在Python安装目录的Scripts目录下~

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

Path后面加上这个路径就好~

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

2.下载浏览器驱动

因为Selenium是不带浏览器的,所以需要依赖第三方的浏览器,要调用第三方 的浏览器的话,需要下载浏览器的驱动,因为笔者用到是Chrome,这里就以 Chrome为例子吧,其他浏览器的自行搜索相关资料了!打开Chrome浏览器,键入:

chrome://version

可以查看Chrome浏览器版本的相关信息,这里主要是关注版本号就行了:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

61,好的,接下来到下面的这个网站查看对应的驱动版本号:

chromedriver.storage.googleapis.com/2.34/notes.…

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

好的,那就下载v2.34版本的浏览器驱动吧:

chromedriver.storage.googleapis.com/index.html?…

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

下载完成后,把zip文件解压下,解压后的 chromedriver.exe 拷贝到Python 的Scripts目录下。(这里不用纠结win32,在64位的浏览器上也是可以正常使用的!)

PS:Mac的话把解压后的文件拷贝到 usr/local/bin 目录下 Ubuntu的话拷贝到: usr/bin 目录下

接下来我们写个简单的代码来测试下:

from selenium import webdriver

browser = webdriver.Chrome()  # 调用本地的Chrome浏览器
browser.get('http://www.baidu.com')  # 请求页面,会打开一个浏览器窗口
html_text = browser.page_source  # 获得页面代码
browser.quit()  # 关闭浏览器
print(html_text)

执行这段代码,会自动调起浏览器,并且访问百度:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

并且控制台会输出HTML的代码,就是直接获取的 Elements页面结构 , JS执行完后的页面~接下来我们就可以来抓我们的煎蛋妹子图啦~

3.Selenium 简单实战:抓取煎蛋妹子图

直接分析 Elements页面结构 ,找到想要的关键结点:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

明显这就是我们抓取的小姐姐图片,复制下这个URL,看下我们打印出的 页面结构有没有这个东西:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

可以,很棒,有这个页面数据,接下来就走一波Beautiful Soup获取到我们 想要的数据啦~

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

经过上面的过滤就能够拿到我们的妹子图片URL:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

随手打开一个验证下,啧啧:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

看了下一页只有30个小姐姐,这显然是满足不了我们的,我们在第一次加载 的时候先拿到一波页码,然后就知道有多少页了,然后自己再去拼接URL加载 不同的页面,比如这里总共又448页:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

拼接成这样的URL即可: http://jandan.net/ooxx/page-448 过滤下拿到页码:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页
小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

接下来就把代码补齐咯,循环抓取每一页的小姐姐,然后下载到本地, 完整代码如下:

import os
from selenium import webdriver
from bs4 import BeautifulSoup
import urllib.request
import ssl
import urllib.error

base_url = 'http://jandan.net/ooxx'
pic_save_path = "output/Picture/JianDan/"


# 下载图片
def download_pic(url):
    correct_url = url
    if url.startswith('//'):
        correct_url = url[2:]
    if not url.startswith('http'):
        correct_url = 'http://' + correct_url
    print(correct_url)
    headers = {
        'Host': 'wx2.sinaimg.cn',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/61.0.3163.100 Safari/537.36 '
    }
    try:
        req = urllib.request.Request(correct_url, headers=headers)
        resp = urllib.request.urlopen(req)
        pic = resp.read()
        pic_name = correct_url.split("/")[-1]
        with open(pic_save_path + pic_name, "wb+") as f:
            f.write(pic)
    except (OSError, urllib.error.HTTPError, urllib.error.URLError, Exception) as reason:
        print(str(reason))


# 打开浏览器模拟请求
def browser_get():
    browser = webdriver.Chrome()
    browser.get('http://jandan.net/ooxx')
    html_text = browser.page_source
    page_count = get_page_count(html_text)
    # 循环拼接URL访问
    for page in range(page_count, 0, -1):
        page_url = base_url + '/page-' + str(page)
        print('解析:' + page_url)
        browser.get(page_url)
        html = browser.page_source
        get_meizi_url(html)
    browser.quit()


# 获取总页码
def get_page_count(html):
    soup = BeautifulSoup(html, 'html.parser')
    page_count = soup.find('span', attrs={'class': 'current-comment-page'})
    return int(page_count.get_text()[1:-1]) - 1


# 获取每个页面的小姐姐
def get_meizi_url(html):
    soup = BeautifulSoup(html, 'html.parser')
    ol = soup.find('ol', attrs={'class': 'commentlist'})
    href = ol.findAll('a', attrs={'class': 'view_img_link'})
    for a in href:
        download_pic(a['href'])


if __name__ == '__main__':
    ssl._create_default_https_context = ssl._create_unverified_context
    if not os.path.exists(pic_save_path):
        os.makedirs(pic_save_path)
    browser_get()

运行结果:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

看下我们输出文件夹~

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

是的,贴那么多小姐姐,就是想 骗你学Python !

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

4.PhantomJS

PhantomJS没有界面的浏览器,特点:会把网站加载到内存并执行页面上的 JavaScript,因为 不会展示图形界面 ,所以运行起来 比完整的浏览器要高效 。 (在一些 Linux 的主机上没有图形化界面,就不能用有界面的浏览器了, 可以通过PhantomJS来规避这个问题)。

Win上安装PhantomJS:

  • 1. 官网下载phantomjs.org/download.ht… 压缩包;
  • 2. 解压 :phantomjs-2.1.1-windows.zip 放到自己想放的位置;
  • 3. 配置环境变量目录/bin 比如我的:
    小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页
  • 4.打开 cmd ,键入: phantomjs --version 验证是否配置成功;
    小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

Ubuntu/MAC上安装PhantomJS:

sudo apt-get install phantomjs

!!!关于PhantomJS的重要说明:

在今年的四月份,Phantom.js的维护者(Maintainer)宣布退出PhantomJS, 意味着这个项目项目可能不会再进行维护了!!! Chrome和FireFox 也开始 提供 Headless模式 (无需吊起浏览器),所以,估计使用PhantomJS的小伙伴 也会慢慢迁移到这两个浏览器上。Windows Chrome需要60以上的版本才支持 Headless模式,启用Headless模式也非常简单:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

selenium官方文档也写了:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

运行的时候也会报这个警告:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

5.Selenium实战:模拟登录CSDN,并保存Cookie

CSDN登录网站: passport.csdn.net/account/log…

分析下页面结构,不难找到对应的登录输入框,以及登录按钮:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页
小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

我们要做的就是在这两个结点输入账号密码,然后触发登录按钮, 同时把Cookie保存到本地,后面就可以带着Cookie去访问相关页面了~

先编写模拟登录的方法吧:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

找到输入账号密码的节点,设置下自己的账号密码,然后找到登录 按钮节点,click一下,然后坐等登录成功,登录成功后可以比较 current_url是否发生了改变。然后把Cookies给保存下来,这里 我用的是pickle库,可以用其他,比如json,或者字符串拼接, 然后保存到本地。如无意外应该是能拿到Cookie的,接着就利用 Cookie去访问主页。

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

通过add_cookies方法来设置Cookie,参数是字典类型的,另外要先 访问get一次链接,再去设置cookie,不然会报无法设置cookie的错误!

看下右下角是否变为登录状态就可以知道是否使用Cookie登录成功了:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

6.Selenium 常用函数

Seleninum作为自动化测试的工具,自然是提供了很多自动化操作的函数, 下面列举下个人觉得比较常用的函数,更多可见官方文档: 官方API文档seleniumhq.github.io/selenium/do…

1) 定位元素

  • find_element_by_class_name :根据class定位
  • find_element_by_css_selector :根据css定位
  • find_element_by_id :根据id定位
  • find_element_by_link_text :根据链接的文本来定位
  • find_element_by_name :根据节点名定位
  • find_element_by_partial_link_text :根据链接的文本来定位,只要包含在整个文本中即可
  • find_element_by_tag_name :通过tag定位
  • find_element_by_xpath :使用Xpath进行定位

PS:把element改为elements会定位所有符合条件的元素,返回一个List 比如: find_elements_by_class_name

2) 鼠标动作

有时需要在页面上模拟鼠标操作,比如:单击,双击,右键,按住,拖拽等 可以导入 ActionChains 类: selenium.webdriver.common.action_chains.ActionChains 使用 ActionChains(driver).XXX 调用对应节点的行为

  • click(element) :单击某个节点;
  • click_and_hold(element) :单击某个节点并按住不放;
  • context_click(element) :右键单击某个节点;
  • double_click(element) :双击某个节点;
  • drag_and_drop(source,target) :按住某个节点拖拽到另一个节点;
  • drag_and_drop_by_offset(source, xoffset, yoffset) :按住节点按偏移拖拽
  • key_down :按下特殊键,只能用(Control, Alt and Shift),比如Ctrl+C ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform();
  • key_up :释放特殊键;
  • move_by_offset(xoffset, yoffset) :按偏移移动鼠标;
  • move_to_element(element) :鼠标移动到某个节点的位置;
  • move_to_element_with_offset(element, xoffset, yoffset) :鼠标移到某个节点并偏移;
  • pause(second) :暂停所有的输入多少秒;
  • perform() :执行操作,可以设置多个操作,调用perform()才会执行;
  • release() :释放鼠标按钮
  • reset_actions :重置操作
  • send_keys(keys_to_send) :模拟按键,比如输入框节点.send_keys(Keys.CONTROL,'a') 全选输入框内容,输入框节点.send_keys(Keys.CONTROL,'x')剪切,模拟回退: 节点.send_keys(keys.RETURN);或者直接设置输入框内容:输入框节点.send_keys('xxx');
  • send_keys_to_element(element, *keys_to_send) :和send_keys类似;

3) 弹窗

对应类:selenium.webdriver.common.alert.Alert,感觉应该用得不多...

如果你触发了某个时间,弹出了对话框,可以调用下述方法获得对话框: alert = driver.switch_to_alert() ,然后可以调用下述方法:

  • accept():确定
  • dismiss():关闭对话框
  • send_keys():传入值
  • text():获得对话框文本

4)页面前进,后退,切换

切换窗口: driver.switch_to. window ("窗口名") 或者通过window_handles来遍历 for handle in driver. window_handles :       driver.switch_to_window(handle) driver. forward () #前进 driver. back () # 后退

5) 页面截图

driver. save_screenshot ("截图.png")

6) 页面等待

现在的网页越来越多采用了 Ajax技术,这样程序便不能确定何时某个元素完全 加载出来了。如果实际页面等待时间过长导致某个dom元素还没出来,但是你的 代码直接使用了这个WebElement,那么就会抛出NullPointer的异常。

为了避免这种元素定位困难而且会提高产生 ElementNotVisibleException 的概率。 所以 Selenium 提供了两种等待方式,一种是 隐式等待 ,一种是 显式等待

显式等待:

显式等待指定某个条件,然后设置最长等待时间。如果在这个时间还没有 找到元素,那么便会抛出异常了。

from selenium import webdriver
from selenium.webdriver.common.by import By
# WebDriverWait 库,负责循环等待
from selenium.webdriver.support.ui import WebDriverWait
# expected_conditions 类,负责条件出发
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.PhantomJS()
driver.get("http://www.xxxxx.com/loading")
try:
    # 每隔10秒查找页面元素 id="myDynamicElement",直到出现则返回
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    driver.quit()

如果不写参数,程序默认会 0.5s 调用一次来查看元素是否已经生成, 如果本来元素就是存在的,那么会立即返回。

下面是一些内置的等待条件,你可以直接调用这些条件,而不用自己 写某些等待条件了。

title_is title_contains presence_of_element_located visibility_of_element_located visibility_of presence_of_all_elements_located text_to_be_present_in_element text_to_be_present_in_element_value frame_to_be_available_and_switch_to_it invisibility_of_element_located element_to_be_clickable – it is Displayed and Enabled. staleness_of element_to_be_selected element_located_to_be_selected element_selection_state_to_be element_located_selection_state_to_be alert_is_present

隐式等待:

隐式等待比较简单,就是简单地设置一个等待时间,单位为秒。

from selenium import webdriver

driver = webdriver.PhantomJS()
driver.implicitly_wait(10) # seconds
driver.get("http://www.xxxxx.com/loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")

当然如果不设置,默认等待时间为0。

7.执行JS语句

driver. execute_script (js语句) 比如滚动到底部: js = document.body.scrollTop=10000 driver.execute_script(js)

小结

本节讲解了一波使用 Selenium 自动化测试框架来抓取JavaScript动态生成数据, Selenium 需依赖于第三方的浏览器,要注意 PhantomJS 无界面浏览器过时的 问题,可以使用Chrome和FireFox提供的 HeadLess 来替换;通过抓取煎蛋妹子 图以及模拟CSDN自动登录的例子来熟悉 Selenium 的基本使用,还是收货良多的。 当然 Selenium 的水还是很深的,当前我们能够使用它来应付JS动态加载数据页面 数据的抓取就够了。

最近天气略冷,各位小伙伴记得适时添衣~ 另外这周因为事比较多,就先断更了,下周再见,接下里要啃的骨头是 Python多线程 ,目测得啃好几节,敬请期待~

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

顺道记录下自己的想到的东西:

  • 1.不是每个网站都是像CSDN一样不需要验证码就能够登录的, 验证码还分几代,普通的数字模糊下,滑条,而像简书掘金用 那种人机检测的是比较新的,目前还不知道怎么解决,有知道 的小伙伴告诉下呗~
  • 2.像掘金,简书等那种抓取文章,为了反爬虫,需要登录才能查看全文...

本节源码下载:

github.com/coder-pig/R…

本节参考文献:

来啊,Py交易啊

欢迎各种像我一样的Py初学者,或者Py大神加入, 一起愉快地交流学♂习:

小猪的Python学习之旅 —— 5.使用Selenium抓取JavaScript动态生成数据的网页

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

PHP for the World Wide Web, Second Edition (Visual QuickStart Gu

PHP for the World Wide Web, Second Edition (Visual QuickStart Gu

Larry Ullman / Peachpit Press / 2004-02-02 / USD 29.99

So you know HTML, even JavaScript, but the idea of learning an actual programming language like PHP terrifies you? Well, stop quaking and get going with this easy task-based guide! Aimed at beginning ......一起来看看 《PHP for the World Wide Web, Second Edition (Visual QuickStart Gu》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具