当前位置: 代码迷 >> 综合 >> 爬虫知识点(ajax异步加载,JavaScript 动态刷新,phantomjs + selenium模拟登陆)
  详细解决方案

爬虫知识点(ajax异步加载,JavaScript 动态刷新,phantomjs + selenium模拟登陆)

热度:83   发布时间:2023-11-20 21:32:09.0

JavaScript

JavaScript 是网络上最常用也是支持者最多的客户端脚本语言。它可以收集 用户的跟踪数据,不需要重载页面直接提交表单,在页面嵌入多媒体文件,甚至运行网页游戏。


Ajax  当你访问一个网页时 鼠标向下滑 数据不断的更新而http网址没有变化,那么这个网页就利用了ajax异步加载技术

我们与网站服务器通信的唯一方式,就是发出 HTTP 请求获取新页面。如果提交表单之后,或从服务器获取信息之后,网站的页面不需要重新刷新,那么你访问的网站就在用Ajax 技术。

Ajax 其实并不是一门语言,而是用来完成网络任务(可以认为 它与网络数据采集差不多)的一系列技术。Ajax 全称是 Asynchronous JavaScript and XML(异步 JavaScript 和 XML),网站不需要使用单独的页面请求就可以和网络服务器进行交互 (收发信息)。

那么,如何搞定?

那些使用了 Ajax 或 DHTML 技术改变 / 加载内容的页面,可能有一些采集手段。但是用 Python 解决这个问题只有两种途径:

  1. 直接从 JavaScript 代码里采集内容(费时费力)
  2. 用 Python 的 第三方库运行 JavaScript,直接采集你在浏览器里看到的页面(这个可以有)。
JS2PY解决了JavaScript中动态变化的cookie

  

微信群里有位朋友Jacky提到爬取中国银行遇到的问题,一时兴起便做了尝试。

  • 首先还原问题,我们禁用js,在chrome浏览器中新建标签页,F12 > F1 >打开设置在右下角找到禁用js并勾选
  • 打开中国人民银行条法司网页发现如下的页面显示
  • 然后F12关闭开发者控制台,刷新页面,显示正常
  • 利用chrome插件,EditThisCookie,在控制台中查看cookie如下,同时禁用js再次打开网页却发现显示正常,而清空cookie(禁用js)后打开又出现问题显示。
  • 这是因为该网页首先传给你的html文件中包含cookie设置和动态跳转网址的js代码,js代码运行后会自动设置cookie并跳转链接,到达正常页面。
  • 我们查看问题页面的源码,Ctrl-U
    Paste_Image.png
  • 源码很乱,以我的菜鸡水平根本看不出来什么东西,这时需要优秀工具的帮助,http://jsbeautifier.org/ 是一款优秀js代码美化和解析工具,我们将代码放上去解析,终端curl网页得到的js代码和解析后的代码对比鲜明
  • 与一般的代码美化工具比较(下图),不仅格式化了代码,并且可读化了代码,这样以我的水平就可以分析代码了。
  • 首先两次请求该网址,将两次美化后的代码进行对比,我们可以看到不仅在js全局变量上有改变,在其中一个加密函数里也有小改动。
  • 某一个请求里的js代码,留存参考,阅读可先跳过:
var dynamicurl = "/L3RpYW9mYXNpLzE0NDk0MS8xNDQ5NTcvaW5kZXguaHRtbA==";
var wzwschallenge = "RANDOMSTR14925";
var wzwschallengex = "STRRANDOM14925";
var template = 4;
var encoderchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";function KTKY2RBD9NHPBCIHV9ZMEQQDARSLVFDU(str) {var out, i, len;var c1, c2, c3;len = str.length;i = 0;out = "";while (i < len) {c1 = str.charCodeAt(i++) & 0xff;if (i == len) {out += encoderchars.charAt(c1 >> 2);out += encoderchars.charAt((c1 & 0x3) << 4);out += "==";break;}c2 = str.charCodeAt(i++);if (i == len) {out += encoderchars.charAt(c1 >> 2);out += encoderchars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4));out += encoderchars.charAt((c2 & 0xf) << 2);out += "=";break;}c3 = str.charCodeAt(i++);out += encoderchars.charAt(c1 >> 2);out += encoderchars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4));out += encoderchars.charAt(((c2 & 0xf) << 2) | ((c3 & 0xc0) >> 6));out += encoderchars.charAt(c3 & 0x3f);}return out;
}function findDimensions() {var w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;var h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;if (w * h <= 120000) {return true;}var x = window.screenX;var y = window.screenY;if (x + w <= 0 || y + h <= 0 || x >= window.screen.width || y >= window.screen.height) {return true;}return false;
}function QWERTASDFGXYSF() {var tmp = wzwschallenge + wzwschallengex;var hash = 0;var i = 0;for (i = 0; i < tmp.length; i++) {hash += tmp.charCodeAt(i);}hash *= 11;hash += 111111;return "WZWS_CONFIRM_PREFIX_LABEL4" + hash;
}function HXXTTKKLLPPP5() {if (findDimensions()) {} else {var cookieString = "";cookieString = "wzwstemplate=" + KTKY2RBD9NHPBCIHV9ZMEQQDARSLVFDU(template.toString()) + "; path=/";document.cookie = cookieString;var confirm = QWERTASDFGXYSF();cookieString = "wzwschallenge=" + KTKY2RBD9NHPBCIHV9ZMEQQDARSLVFDU(confirm.toString()) + "; path=/";document.cookie = cookieString;window.location = dynamicurl;}
}
HXXTTKKLLPPP5();
  • 这种程度的js代码(美化后)并不难理解,很明显可以看出最后的函数调用中利用document.cookie设置了两个cookie,并利用window.location设置了跳转网址,静下心去分析也能用python写出相应的加密程序,用正则取配到变量,生成我们想要的信息,但是有没有更快的方法呢。这时我们又有一个强大的工具,Js2Py,利用它我们可以解析js代码变为python中的可执行代码。如下官方简单示例:

  • 下面的思路就清晰了,先利用js美化工具的python库jsbeautifier(pip安装)美化代码,然后不管js代码中关于dom操作的内容(如window.xx),取出js全局变量和加密函数,利用js2py生成可执行的python函数,以js代码中的主干逻辑在python里执行获得cookies,在requests.session中更新cookies并访问js变量中的动态网址,就可以成功到达内容页,开始爬取解析了。
  • 以下为python代码,可以看到最后成功验证我们爬取到了有效信息。
import requests
import re
import jsbeautifier
import js2pyhost_url = 'http://www.pbc.gov.cn/'
dest_url = 'http://www.pbc.gov.cn/tiaofasi/144941/144957/index.html'
# 利用session保存cookie信息,第一次请求会设置cookie类似{'wzwsconfirm': 'ab3039756ba3ee041f7e68f634d28882', 'wzwsvtime': '1488938461'},与js解析得到的cookie合起来才能通过验证
r = requests.session()
content = r.get(dest_url).content
# 获取页面脚本内容
re_script = re.search(r'<script type="text/javascript">(?P<script>.*)</script>', content.decode('utf-8'), flags=re.DOTALL)
# 用点匹配所有字符,用(?P<name>...)获取:https://docs.python.org/3/howto/regex.html#regex-howto
# cheatsheet:https://github.com/tartley/python-regex-cheatsheet/blob/master/cheatsheet.rst
script = re_script.group('script')
script = script.replace('\r\n', '')
# 在美化之前,去掉\r\n之类的字符才有更好的效果
res = jsbeautifier.beautify(script)
# 美化并一定程度解析js代码:https://github.com/beautify-web/js-beautify
with open('x.js','w') as f:f.write(res)
# 写入文档进行查看分析jscode_list = res.split('function')
var_ = jscode_list[0]
var_list = var_.split('\n')
template_js = var_list[3] # 依顺序获取,亦可用正则
template_py = js2py.eval_js(template_js)
# 将所有全局变量插入第一个函数变为局部变量并计算
function1_js = 'function' + jscode_list[1]
position = function1_js.index('{') +1
function1_js = function1_js[:position]+ var_ +function1_js[position:]
function1_py = js2py.eval_js(function1_js)
cookie1 = function1_py(str(template_py)) # 结果类似'NA=='
# 保存得到的第一个cookie
cookies = {}
cookies['wzwstemplate'] = cookie1
# 对第三个函数做类似操作
function3_js = 'function' + jscode_list[3]
position = function3_js.index('{') +1
function3_js = function3_js[:position]+ var_ +function3_js[position:]
function3_py = js2py.eval_js(function3_js)
middle_var = function3_py() # 是一个str变量,结果类似'WZWS_CONFIRM_PREFIX_LABEL4132209'
cookie2 = function1_py(middle_var)
cookies['wzwschallenge'] = cookie2
# 关于js代码中的document.cookie参见 https://developer.mozilla.org/zh-CN/docs/Web/API/Document/cookie
dynamicurl = js2py.eval_js(var_list[0])# 利用新的cookie对提供的动态网址进行访问即是我们要达到的内容页面了
r.cookies.update(cookies)
content = r.get(host_url+dynamicurl).content# 最后验证是否爬取到有效信息
if u'银行卡清算机构管理办法' in content.decode('utf-8'):print('success'


作者:treelake
链接:http://www.jianshu.com/p/f5854aed87c8
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Selenium

Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,类型像我们玩游戏用的按键精灵,可以按指定的命令自动操作,不同是Selenium 可以直接运行在浏览器上,它支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器)。

Selenium 可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。

Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。但是我们有时候需要让它内嵌在代码中运行,所以我们可以用一个叫 PhantomJS 的工具代替真实的浏览器。

可以从 PyPI 网站下载 Selenium库https://pypi.python.org/simple/selenium ,也可以用 第三方管理器 pip用命令安装:pip install selenium

Selenium 官方参考文档:http://selenium-python.readthedocs.io/index.html

PhantomJS

PhantomJS 是一个基于Webkit的“无界面”(headless)浏览器,它会把网站加载到内存并执行页面上的 JavaScript,因为不会展示图形界面,所以运行起来比完整的浏览器要高效。

如果我们把 Selenium 和 PhantomJS 结合在一起,就可以运行一个非常强大的网络爬虫了,这个爬虫可以处理 JavaScrip、Cookie、headers,以及任何我们真实用户需要做的事情。

注意:PhantomJS 只能从它的官方网站http://phantomjs.org/download.html) 下载。 因为 PhantomJS 是一个功能完善(虽然无界面)的浏览器而非一个 Python 库,所以它不需要像 Python 的其他库一样安装,但我们可以通过Selenium调用PhantomJS来直接使用。

PhantomJS 官方参考文档:http://phantomjs.org/documentation

快速入门

Selenium 库里有个叫 WebDriver 的 API。WebDriver 有点儿像可以加载网站的浏览器,但是它也可以像 BeautifulSoup 或者其他 Selector 对象一样用来查找页面元素,与页面上的元素进行交互 (发送文本、点击等),以及执行其他动作来运行网络爬虫。

# IPython2 测试代码# 导入 webdriver
from selenium import webdriver# 要想调用键盘按键操作需要引入keys包
from selenium.webdriver.common.keys import Keys# 调用环境变量指定的PhantomJS浏览器创建浏览器对象
driver = webdriver.PhantomJS()# 如果没有在环境变量指定PhantomJS位置
# driver = webdriver.PhantomJS(executable_path="./phantomjs"))# get方法会一直等到页面被完全加载,然后才会继续程序,通常测试会在这里选择 time.sleep(2)
driver.get("http://www.baidu.com/")# 获取页面名为 wrapper的id标签的文本内容
data = driver.find_element_by_id("wrapper").text# 打印数据内容
print data# 打印页面标题 "百度一下,你就知道"
print driver.title# 生成当前页面快照并保存
driver.save_screenshot("baidu.png")# id="kw"是百度搜索输入框,输入字符串"长城"
driver.find_element_by_id("kw").send_keys(u"长城")# id="su"是百度搜索按钮,click() 是模拟点击
driver.find_element_by_id("su").click()# 获取新的页面快照
driver.save_screenshot("长城.png")# 打印网页渲染后的源代码
print driver.page_source# 获取当前页面Cookie
print driver.get_cookies()# ctrl+a 全选输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')# ctrl+x 剪切输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'x')# 输入框重新输入内容
driver.find_element_by_id("kw").send_keys("itcast")# 模拟Enter回车键
driver.find_element_by_id("su").send_keys(Keys.RETURN)# 清除输入框内容
driver.find_element_by_id("kw").clear()# 生成新的页面快照
driver.save_screenshot("itcast.png")# 获取当前url
print driver.current_url# 关闭当前页面,如果只有一个页面,会关闭浏览器
# driver.close()# 关闭浏览器
driver.quit()

页面操作

Selenium 的 WebDriver提供了各种方法来寻找元素,假设下面有一个表单输入框:

<input type="text" name="user-name" id="passwd-id" />

那么:

# 获取id标签值
element = driver.find_element_by_id("passwd-id")
# 获取name标签值
element = driver.find_element_by_name("user-name")
# 获取标签名值
element = driver.find_elements_by_tag_name("input")
# 也可以通过XPath来匹配
element = driver.find_element_by_xpath("//input[@id='passwd-id']")

定位UI元素 (WebElements)

关于元素的选取,有如下的API 单个元素选取
find_element_by_id
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector
  1. By ID

    <div id="coolestWidgetEvah">...</div>
    
    • 实现

      element = driver.find_element_by_id("coolestWidgetEvah")
      ------------------------ or -------------------------
      from selenium.webdriver.common.by import By
      element = driver.find_element(by=By.ID, value="coolestWidgetEvah")
      
  1. By Class Name

    <div class="cheese"><span>Cheddar</span></div><div class="cheese"><span>Gouda</span></div>
    
    • 实现

      cheeses = driver.find_elements_by_class_name("cheese")
      ------------------------ or -------------------------
      from selenium.webdriver.common.by import By
      cheeses = driver.find_elements(By.CLASS_NAME, "cheese")
      
  2. By Tag Name

    <iframe src="..."></iframe>
    
    • 实现

      frame = driver.find_element_by_tag_name("iframe")
      ------------------------ or -------------------------
      from selenium.webdriver.common.by import By
      frame = driver.find_element(By.TAG_NAME, "iframe")
      
  3. By Name

    <input name="cheese" type="text"/>
    
    • 实现

      cheese = driver.find_element_by_name("cheese")
      ------------------------ or -------------------------
      from selenium.webdriver.common.by import By
      cheese = driver.find_element(By.NAME, "cheese")
      
  4. By Link Text

    <a href="http://www.google.com/search?q=cheese">cheese</a>
    
    • 实现

      cheese = driver.find_element_by_link_text("cheese")
      ------------------------ or -------------------------
      from selenium.webdriver.common.by import By
      cheese = driver.find_element(By.LINK_TEXT, "cheese")
      
  5. By Partial Link Text

    <a href="http://www.google.com/search?q=cheese">search for cheese</a>>
    
    • 实现

      cheese = driver.find_element_by_partial_link_text("cheese")
      ------------------------ or -------------------------
      from selenium.webdriver.common.by import By
      cheese = driver.find_element(By.PARTIAL_LINK_TEXT, "cheese")
      
  6. By CSS

    <div id="food"><span class="dairy">milk</span><span class="dairy aged">cheese</span></div>
    
    • 实现

      cheese = driver.find_element_by_css_selector("#food span.dairy.aged")
      ------------------------ or -------------------------
      from selenium.webdriver.common.by import By
      cheese = driver.find_element(By.CSS_SELECTOR, "#food span.dairy.aged")
      
  7. By XPath

    <input type="text" name="example" />
    <INPUT type="text" name="other" />
    
    • 实现

      inputs = driver.find_elements_by_xpath("//input")
      ------------------------ or -------------------------
      from selenium.webdriver.common.by import By
      inputs = driver.find_elements(By.XPATH, "//input")
      

鼠标动作链

有些时候,我们需要再页面上模拟一些鼠标操作,比如双击、右击、拖拽甚至按住不动等,我们可以通过导入 ActionChains 类来做到:

示例:


#导入 ActionChains 类
from selenium.webdriver import ActionChains# 鼠标移动到 ac 位置
ac = driver.find_element_by_xpath('element')
ActionChains(driver).move_to_element(ac).perform()# 在 ac 位置单击
ac = driver.find_element_by_xpath("elementA")
ActionChains(driver).move_to_element(ac).click(ac).perform()# 在 ac 位置双击
ac = driver.find_element_by_xpath("elementB")
ActionChains(driver).move_to_element(ac).double_click(ac).perform()# 在 ac 位置右击
ac = driver.find_element_by_xpath("elementC")
ActionChains(driver).move_to_element(ac).context_click(ac).perform()# 在 ac 位置左键单击hold住
ac = driver.find_element_by_xpath('elementF')
ActionChains(driver).move_to_element(ac).click_and_hold(ac).perform()# 将 ac1 拖拽到 ac2 位置
ac1 = driver.find_element_by_xpath('elementD')
ac2 = driver.find_element_by_xpath('elementE')
ActionChains(driver).drag_and_drop(ac1, ac2).perform()

填充表单

我们已经知道了怎样向文本框中输入文字,但是有时候我们会碰到<select> </select>标签的下拉框。直接点击下拉框中的选项不一定可行。

<select id="status" class="form-control valid" onchange="" name="status"><option value=""></option><option value="0">未审核</option><option value="1">初审通过</option><option value="2">复审通过</option><option value="3">审核不通过</option>
</select>

Selenium专门提供了Select类来处理下拉框。 其实 WebDriver 中提供了一个叫 Select 的方法,可以帮助我们完成这些事情:

# 导入 Select 类
from selenium.webdriver.support.ui import Select# 找到 name 的选项卡
select = Select(driver.find_element_by_name('status'))# 
select.select_by_index(1)
select.select_by_value("0")
select.select_by_visible_text(u"未审核")

以上是三种选择下拉框的方式,它可以根据索引来选择,可以根据值来选择,可以根据文字来选择。注意:

  • index 索引从 0 开始
  • value是option标签的一个属性值,并不是显示在下拉框中的值
  • visible_text是在option标签文本的值,是显示在下拉框的值

全部取消选择怎么办呢?很简单:

select.deselect_all()

弹窗处理

当你触发了某个事件之后,页面出现了弹窗提示,处理这个提示或者获取提示信息方法如下:

alert = driver.switch_to_alert()

页面切换

一个浏览器肯定会有很多窗口,所以我们肯定要有方法来实现窗口的切换。切换窗口的方法如下:

driver.switch_to.window("this is window name")

也可以使用 window_handles 方法来获取每个窗口的操作对象。例如:

for handle in driver.window_handles:driver.switch_to_window(handle)

页面前进和后退

操作页面的前进和后退功能:

driver.forward()     #前进
driver.back()        # 后退

Cookies

获取页面每个Cookies值,用法如下

for cookie in driver.get_cookies():print "%s -> %s" % (cookie['name'], cookie['value'])

删除Cookies,用法如下

# By name
driver.delete_cookie("CookieName")# all
driver.delete_all_cookies()

页面等待

注意:这是非常重要的一部分!!

现在的网页越来越多采用了 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 ECdriver = webdriver.Chrome()
driver.get("http://www.xxxxx.com/loading")
try:# 页面一直循环,直到 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 webdriverdriver = webdriver.Chrome()
driver.implicitly_wait(10) # seconds
driver.get("http://www.xxxxx.com/loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")

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


案例一:网站模拟登录
# douban.py

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import timedriver = webdriver.PhantomJS()
driver.get("http://www.douban.com")

# 输入账号密码
driver.find_element_by_name("form_email").send_keys("xxxxx@xxxx.com")
driver.find_element_by_name("form_password").send_keys("xxxxxxxx")

# 模拟点击登录
driver.find_element_by_xpath("//input[@class='bn-submit']").click()

# 等待3秒
time.sleep(3)

# 生成登陆后快照
driver.save_screenshot("douban.png")

with open("douban.html", "w") as file:  file.write(driver.page_source)

driver.quit()

案例三:执行 JavaScript 语句

    1. 隐藏百度图片

from selenium import webdriverdriver = webdriver.PhantomJS()
driver.get("https://www.baidu.com/")# 给搜索输入框标红的javascript脚本
js = "var q=document.getElementById(\"kw\");q.style.border=\"2px solid red\";"# 调用给搜索输入框标红js脚本
driver.execute_script(js)#查看页面快照
driver.save_screenshot("redbaidu.png")#js隐藏元素,将获取的图片元素隐藏
img = driver.find_element_by_xpath("//*[@id='lg']/img")
driver.execute_script('$(arguments[0]).fadeOut()',img)# 向下滚动到页面底部
driver.execute_script("$('.scroll_top').click(function(){$('html,body').animate({scrollTop: '0px'}, 800);});")#查看页面快照
driver.save_screenshot("nullbaidu.png")driver.quit()
    1. 模拟滚动条滚动到底部
# 
from selenium import webdriver
import timedriver = webdriver.PhantomJS()
driver.get("https://movie.douban.com/typerank?type_name=剧情&type=11&interval_id=100:90&action=")# 向下滚动10000像素
js = "document.body.scrollTop=10000"
#js="var q=document.documentElement.scrollTop=10000"
time.sleep(3)#查看页面快照
driver.save_screenshot("douban.png")# 执行JS语句
driver.execute_script(js)
time.sleep(10)#查看页面快照
driver.save_screenshot("newdouban.png")driver.quit()
斗鱼直播案例
import unittest
from selenium import webdriver
from bs4 import BeautifulSoup as bsclass douyu(unittest.TestCase):  # 初始化方法,必须是setUp()
    def setUp(self):  self.driver = webdriver.PhantomJS(executable_path=r"D:\mulu\phantomjs-2.1.1-windows\phantomjs-2.1.1-windows\bin")
        self.num = 0
        self.count = 0

    # 测试方法必须有test字样开头
    def testDouyu(self):  self.driver.get("https://www.douyu.com/directory/all")

        while True:  soup = bs(self.driver.page_source, "lxml")
            # 房间名, 返回列表
            names = soup.find_all("h3", {
    "class" : "ellipsis"})
            # 观众人数, 返回列表
            numbers = soup.find_all("span", {
    "class" :"dy-num fr"})

            # zip(names, numbers) 将name和number这两个列表合并为一个元组 : [(1, 2), (3, 4)...]
            for name, number in zip(names, numbers):  print u"观众人数: -" + number.get_text().strip() + u"-\t房间名: " + name.get_text().strip()
                self.num += 1
                #self.count += int(number.get_text().strip())

            # 如果在页面源码里找到"下一页"为隐藏的标签,就退出循环
            if self.driver.page_source.find("shark-pager-disable-next") != -1:  break   # 一直点击下一页
            self.driver.find_element_by_class_name("shark-pager-next").click()

    # 测试结束执行的方法
    def tearDown(self):  # 退出PhantomJS()浏览器
        print "当前网站直播人数" + str(self.num)
        print "当前网站观众人数" + str(self.count)
        self.driver.quit()

if __name__ == "__main__":  # 启动测试模块
    unittest.main()


  相关解决方案