Qingquan-Li / blog

My Blog
https://Qingquan-Li.github.io/blog/
132 stars 16 forks source link

Selenium+PhantomJS模拟登录 #127

Open Qingquan-Li opened 5 years ago

Qingquan-Li commented 5 years ago

一、开发环境

Selenium (可以通过pip、conda包管理器安装)最起初是为网站自动化测试而开发的,Selenium 可以操作浏览器:让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。 现在,Selenium 已经演变成一个强大的网络数据采集工具。 Selenium 自己不带浏览器,它需要与第三方浏览器结合一起使用。

为了更高效执行程序,这里使用一个叫 PhantomJS 的工具代替真实的有可视化界面的浏览器。 PhantomJS 是一个"无头"(headless)浏览器。它会把网站加载到内存并执行页面上的 Javascript。 把 Selenium 和 PhantomJS 结合在一起,就可以运行一个非常强大的网络爬虫了,可以处理 cookie、Javascript、header ,以及任何你需要的事情。


注意:

2018年3月4日PhantomJS暂停开发,新版本的Selenium不再支持PhantomJS,并建议使用Chrome或Firefox的无头版本来替代PhantomJS。

如果需要继续使用PhantomJS,可以安装旧版本的Selenium(晚于2018.3.4的版本),通过 https://selenium-release.storage.googleapis.com/index.htmlconda search selenium 查看 Selenium 版本。

$ conda install selenium=3.0.1=py35_0


Selenium+PhantomJS模拟登录:

Selenium 适用于爬取使用 Javascript 加载内容的网站。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

'''
Requesrs模块可以处理部分cookie问题。
但是,因为Requests模块不能执行Javascript,Requests不能处理很多新式的跟踪软件生成的cookie(比如Google Analytics)、只有
当客户端脚本执行后才设置cookie(或者在用户浏览页面时基于网页事件产生cookie,比如点击按钮)。
Requests模块不能执行Javascript,而现代网站普遍使用了Ajax异步加载内容。
为了处理这些动作,需要用到Selenium和PhantomJS包。
'''

# 使用PhantomJS库创建一个新的Selenium WebDriver
driver = webdriver.PhantomJS(executable_path='<Path to PhantomJS>')
# 使用WebDriver加载页面
driver.get('<url>')
# driver.implicitly_wait(10) # 隐式等待10秒

print('首页登录页面cookies:')
print(driver.get_cookies())
# 截屏(登录前)
driver.get_screenshot_as_file('./crawling_login_selenium01.png')

username_field = driver.find_element_by_id('username')
password_field = driver.find_element_by_id('password')
submit_button = driver.find_element_by_tag_name('button')

# 清空输入框(某些登录页面,二次登录时会记住用户名,如果不清除,则会在记住的用户名后追加用户名)
username_field.clear()

username_field.send_keys('<username>')
password_field.send_keys('<password>')
# 截屏(登录中)
driver.get_screenshot_as_file('./crawling_login_selenium02.png')
submit_button.click()

try:
    # WebDriverWait和expected_conditions两个模块组合起来构成Selenium的显式等待
    # github.com/FatliTalk/blog/issues/125
    # 下面的visit-list-talbe是登录后页面才加载出来的某个元素的id
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, 'visit-list-talbe'))
    )
except Exception as e:
    print('抛出异常:')
    print(e)
finally:
    print('登录后页面cookies:')
    print(driver.get_cookies())
    # 截屏(登录后)
    driver.get_screenshot_as_file('./crawling_login_selenium03.png')
    # print(element.text) # 等同于print(driver.find_element_by_id('visit-list-talbe').text)
    # 下面的tbody是登录后的页面的某个标签名
    print(driver.find_element_by_tag_name('tbody').text)
    # print(driver.find_element(By.TAG_NAME, 'tbody').text) # 作用同上
    driver.quit() # Quits the driver and closes every associated window.
    # driver.close() # Closes the current window.


Selenium 的选择器

BeautifulSoup 使用 findfind_all 等选择器来选择页面的元素(element)。Selenium 在 WebDriver 的 DOM 中使用了全新的选择器来查找元素,例如上面模拟登录的代码块中使用的 find_element_by_idfind_element_by_tag_name

另外,如果依然想用 BeautifulSoup 来解析网页内容,可以用 WebDriver 的 page_source 函数返回页面的源代码字符串。

page_sources = driver.page_source
bs_obj = BeautifulSoup(page_sources)
print(bs_obj.find(id='visit-list-talbe').get_text())

Selenium的 .text 函数类似于 BeautifulSoup 的 get_text() 函数,清除 HTML 文档中的标签,返回字符串类型的文本内容。


Selenium 的定位器

大多数的期望条件(expected_conditions)在使用都需要先指定等待的目标元素,元素用定位器(locator)指定。

定位器不同于选择器,定位器是一种抽象的查询语言,用 By 对象表示。

例如上面模拟登录的代码块中,一个定位器被用来查找 IDvisit-list-talbe 的内容:

EC.presence_of_element_located((By.ID, 'visit-list-talbe'))

定位器还可以用来创建选择器,配合 WebDriver 的 find_element 函数使用:

print(driver.find_element(By.TAG_NAME, 'tbody').text)

下面这行代码效果和上面一行的代码作用一样:

print(driver.find_element_by_tag_name('tbody').text)

了解更多: