Python+Selenium自动化测试详解selenium相关文档及selenium教程(python)

Python+Selenium自动化测试详解selenium相关文档

 

selenium相关文档:

         https://www.seleniumhq.org/docs/

         https://selenium-python.readthedocs.io

 

一、简介

网页三元素:

  • html负责内容
  • css负责样式
  • JavaScript负责动作;

 

从数据的角度考虑,网页上呈现出来的数据的来源:

  • html文件
  • ajax接口
  • javascript加载

 

如果用requests对一个页面发送请求,只能获得当前加载出来的部分页面,动态加载的数据是获取不到的,比如下拉滚轮得到的数据。selenium最初是一个自动化测试工具, 而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题。selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器。Selenium是python的一个第三方库,对外提供的接口可以操作浏览器,然后让浏览器完成自动化的操作。

selenium在爬虫中的应用:

  • 模拟登录
  • 便捷的获取动态加载的数据

缺点:

  • 爬取数据的效率底
  • 环境部署繁琐

二、环境安装

 

查看谷歌浏览器版本

 

 

 

 

 

 

下载好以后,就有驱动程序了。

 

三、基本使用

1.浏览器创建

Selenium支持非常多的浏览器,如Chrome、Firefox、Edge等,还有Android、BlackBerry等手机端的浏览器。另外,也支持无界面浏览器PhantomJS。

复制代码
from selenium import webdriver

browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.PhantomJS()
browser = webdriver.Safari()
browser.quit()               # 关闭浏览器
browser.close()              # 关闭当前页面     
复制代码

 close 只会关闭当前窗口,而 quit 退出驱动并会关闭所有的窗口。

2.打开网页

browser.get(url)                         # 打开path路径
page_text = browser.page_source                # 获取当前浏览器页面的源码数据

3.元素定位

查找一个元素(单节点)

复制代码
element = find_element_by_id()
element = find_element_by_name()
element = find_element_by_class_name()
element = find_element_by_tag_name()
element = find_element_by_link_text()
element = find_element_by_partial_link_text()
element = find_element_by_xpath()
element = find_element_by_css_selector()
复制代码

查找多个元素(多节点)

复制代码
element = find_elements_by_id()
element = find_elements_by_name()
element = find_elements_by_class_name()
element = find_elements_by_tag_name()
element = find_elements_by_link_text()
element = find_elements_by_partial_link_text()
element = find_elements_by_xpath()
element = find_elements_by_css_selector()
复制代码

注意:

(1)find_element_by_xxx第一个符合条件的标签,find_elements_by_xxx找的是所有符合条件的标签。

(2)根据ID、CSS选择器和XPath获取,它们返回的结果完全一致。

(3)另外,Selenium还提供了通用方法find_element(),它需要传入两个参数:查找方式By和值。实际上,它就是find_element_by_id()这种方法的通用函数版本,比如find_element_by_id(id)就等价于find_element(By.ID, id),二者得到的结果完全一致。 

复制代码
# 通过id定位
<html>
 <body>
  <form id="loginForm">
   <input name="username" type="text" />
   <input name="password" type="password" />
   <input name="continue" type="submit" value="Login" />
  </form>
 </body>
<html>

login_form = driver.find_element_by_id('loginForm')


# 通过name定位 <html> <body> <form id="loginForm"> <input name="username" type="text" /> <input name="password" type="password" /> <input name="continue" type="submit" value="Login" /> <input name="continue" type="button" value="Clear" /> </form> </body> <html> username = driver.find_element_by_name('username') password = driver.find_element_by_name('password')

# 通过链接文本定位 <html> <body> <p>Are you sure you want to do this?</p> <a href="continue.html">Continue</a> <a href="cancel.html">Cancel</a> </body> <html> continue_link = driver.find_element_by_link_text('Continue') continue_link = driver.find_element_by_partial_link_text('Conti')

# 通过标签名定位 <html> <body> <h1>Welcome</h1> <p>Site content goes here.</p> </body> <html> heading1 = driver.find_element_by_tag_name('h1')

# 通过类名定位 <html> <body> <p class="content">Site content goes here.</p> </body> <html> content = driver.find_element_by_class_name('content')

# 通过CSS选择器定位 <html> <body> <p class="content">Site content goes here.</p> </body> <html> content = driver.find_element_by_css_selector('p.content') # 推荐使用xpath定位 username = driver.find_element_by_xpath("//form[input/@name='username']") username = driver.find_element_by_xpath("//form[@id='loginForm']/input[1]") username = driver.find_element_by_xpath("//input[@name='username']")
复制代码

4.节点操作 

ele.text 拿到节点的内容 (包括后代节点的所有内容)

driver.find_element_by_id('gin').text 

ele.send_keys("")搜索框输入文字

driver.find_element_by_id('kw').send_keys("Python") 

ele.click()标签

driver.find_element_by_id('su').click() 

ele.get_attribute("")获取属性值

复制代码
#  获取元素标签的内容
att01 = a.get_attribute('textContent')

# # 获取元素内的全部HTML
att02 = a.get_attribute('innerHTML')

# # 获取包含选中元素的HTML
att03 = a.get_attribute('outerHTML')

# 获取该元素的标签类型
tag01 = a_href.tag_name
复制代码

5.动作链

复制代码
from selenium.webdriver import ActionChains

source = browser.find_element_by_css_selector('')
target = browser.find_element_by_css_selector('')

actions = ActionChains(browser)
actions.drag_and_drop(source, target).perform()

actions.release()
复制代码

6.在页面间切换

适用与页面中点开链接出现新的页面的网站,但是浏览器对象browser还是之前页面的对象

window_handles = driver.window_handles
driver.switch_to.window(window_handles[-1])

7.保存网页截图

driver.save_screenshot('screen.png')

8.执行JavaScript

browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')

9.前进和后退

browser.back()
browser.forward()

10.等待

复制代码
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


driver = webdriver.Chrome()
driver.get("http://somedomain/")
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    driver.quit()
复制代码

条件

 View Code

11.Cookie处理

获取、添加、删除Cookies

browser.get_cookies()
browser.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'germey'})
browser.delete_all_cookies()

12. 搜索属性值

  • 获得element之后搜索 
url = driver.find_element_by_name('t2').get_attribute('href')
  • 页面源码中搜索
复制代码
源码中搜索字符串,可以是文本值也可以是属性值
res = driver.page_source.find('字符串')

返回值
    -1      未找到
    其他     找到
复制代码

13.谷歌无头浏览器

复制代码
from selenium.webdriver.chrome.options import Options。

chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
browser = webdriver.Chrome(executable_path=path, chrome_options=chrome_options)
复制代码

14.规避监测

相关的网站会对selenium发起的请求进行监测,网站后台可以根据window.navigator.webdriver返回值进行selenium的监测,若返回值为undefinded,则不是selenium进行的请求发送;若为true,则是selenium发起的请求。

规避监测的方法:

from selenium.webdriver import ChromeOptions

option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
bro = webdriver.Chrome(executable_path='chromedriver.exe',options=option)

15. 切换子框架

此操作主要作用与 ifram子框架 的互相切换使用

iframe = driver.find_element_by_xxx('')
driver.switch_to_frame(节点对象)

16. 不请求图片模式

只需要如下设置则不会请求图片, 会加快效率

chrome_opt = webdriver.ChromeOptions()
prefs = {"profile.managed_default_content_settings.images": 2}
chrome_opt.add_experimental_option("prefs", prefs)

 

四、鼠标键盘操作(ActionChains)

1. ActionChains基本用法

ActionChains的执行原理:当你调用ActionChains的方法时,不会立即执行,而是会将所有的操作按顺序存放在一个队列里当你调用perform()方法时,队列中的时间会依次执行

 

有两种调用方法:

链式写法

menu = driver.find_element_by_css_selector(".nav")
hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1")

ActionChains(driver).move_to_element(menu).click(hidden_submenu).perform()

分步写法

复制代码
menu = driver.find_element_by_css_selector(".nav")
hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1")

actions = ActionChains(driver)
actions.move_to_element(menu)
actions.click(hidden_submenu)
actions.perform()
复制代码

两种写法本质是一样的,ActionChains都会按照顺序执行所有的操作。

 

2. ActionChains方法列表

复制代码
click(on_element=None)                       ——单击鼠标左键
click_and_hold(on_element=None)                  ——点击鼠标左键,不松开
context_click(on_element=None)                  ——点击鼠标右键
double_click(on_element=None)                   ——双击鼠标左键

send_keys(*keys_to_send)                     ——发送某个键到当前焦点的元素
send_keys_to_element(element, *keys_to_send)         ——发送某个键到指定元素

key_down(value, element=None)                   ——按下某个键盘上的键
key_up(value, element=None)                    ——松开某个键

drag_and_drop(source, target)                   ——拖拽到某个元素然后松开
drag_and_drop_by_offset(source, xoffset, yoffset)      ——拖拽到某个坐标然后松开
move_by_offset(xoffset, yoffset)                ——鼠标从当前位置移动到某个坐标
move_to_element(to_element)                   ——鼠标移动到某个元素
move_to_element_with_offset(to_element, xoffset, yoffset) ——移动到距某个元素(左上角坐标)多少距离的位置

perform()                              ——执行链中的所有动作
release(on_element=None)                     ——在某个元素位置松开鼠标左键 
复制代码

3. 代码示例

(1)点击操作

复制代码
# -*- coding: utf-8 -*-

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from time import sleep


driver = webdriver.Firefox()
driver.implicitly_wait(10)
driver.maximize_window()
driver.get('http://sahitest.com/demo/clicks.htm')

click_btn = driver.find_element_by_xpath('//input[@value="click me"]')          # 单击按钮
doubleclick_btn = driver.find_element_by_xpath('//input[@value="dbl click me"]')    # 双击按钮
rightclick_btn = driver.find_element_by_xpath('//input[@value="right click me"]')    # 右键单击按钮


ActionChains(driver).click(click_btn).double_click(doubleclick_btn).context_click(rightclick_btn).perform()  # 链式用法

print driver.find_element_by_name('t2').get_attribute('value')

sleep(2)
driver.quit()
复制代码

element.get_attribute()获取某个元素属性

(2)鼠标移动

复制代码
# -*- coding: utf-8 -*-

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from time import sleep

driver = webdriver.Firefox()
driver.implicitly_wait(10)
driver.maximize_window()
driver.get('http://sahitest.com/demo/mouseover.htm')

write = driver.find_element_by_xpath('//input[@value="Write on hover"]') # 鼠标移动到此元素,在下面的input框中会显示“Mouse moved”
blank = driver.find_element_by_xpath('//input[@value="Blank on hover"]') # 鼠标移动到此元素,会清空下面input框中的内容

result = driver.find_element_by_name('t1')

action = ActionChains(driver)
action.move_to_element(write).perform()                      # 移动到write,显示“Mouse moved”
print result.get_attribute('value')

# action.move_to_element(blank).perform()
action.move_by_offset(10, 50).perform()                      # 移动到距离当前位置(10,50)的点,与上句效果相同,移动到blank上,清空
print result.get_attribute('value')

action.move_to_element_with_offset(blank, 10, -40).perform() # 移动到距离blank元素(10,-40)的点,可移动到write上
print result.get_attribute('value')

sleep(2)
复制代码

(3)拖拽

复制代码
# -*- coding: utf-8 -*-

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from time import sleep

driver = webdriver.Firefox()
driver.implicitly_wait(10)
driver.maximize_window()
driver.get('http://sahitest.com/demo/dragDropMooTools.htm')

dragger = driver.find_element_by_id('dragger')                 # 被拖拽元素
item1 = driver.find_element_by_xpath('//div[text()="Item 1"]') # 目标元素1
item2 = driver.find_element_by_xpath('//div[text()="Item 2"]') # 目标2
item3 = driver.find_element_by_xpath('//div[text()="Item 3"]') # 目标3
item4 = driver.find_element_by_xpath('//div[text()="Item 4"]') # 目标4

action = ActionChains(driver)
action.drag_and_drop(dragger, item1).perform()                              # 1.移动dragger到item1
sleep(2)
action.click_and_hold(dragger).release(item2).perform()                     # 2.效果与上句相同,也能起到移动效果
sleep(2)
action.click_and_hold(dragger).move_to_element(item3).release().perform()   # 3.效果与上两句相同,也能起到移动的效果
sleep(2)
# action.drag_and_drop_by_offset(dragger, 400, 150).perform()               # 4.移动到指定坐标
action.click_and_hold(dragger).move_by_offset(400, 150).release().perform() # 5.与上一句相同,移动到指定坐标
sleep(2)
driver.quit()
复制代码

一般用坐标定位很少,用上例中的方法1足够了,如果看源码,会发现方法2其实就是方法1中的drag_and_drop()的实现。注意:拖拽使用时注意加等待时间,有时会因为速度太快而失败。

(4)按键

  模拟按键有多种方法,能用win32api来实现,能用SendKeys来实现,也可以用selenium的WebElement对象的send_keys()方法来实现,这里ActionChains类也提供了几个模拟按键的方法。

复制代码
# -*- coding: utf-8 -*-

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from time import sleep

driver = webdriver.Firefox()
driver.implicitly_wait(10)
driver.maximize_window()
driver.get('http://sahitest.com/demo/keypress.htm')

key_up_radio = driver.find_element_by_id('r1')                         # 监测按键升起
key_down_radio = driver.find_element_by_id('r2')                       # 监测按键按下
key_press_radio = driver.find_element_by_id('r3')                      # 监测按键按下升起

enter = driver.find_elements_by_xpath('//form[@name="f1"]/input')[1]   # 输入框
result = driver.find_elements_by_xpath('//form[@name="f1"]/input')[0]  # 监测结果

# 监测key_down
key_down_radio.click()
ActionChains(driver).key_down(Keys.CONTROL, enter).key_up(Keys.CONTROL).perform()
print result.get_attribute('value')

# 监测key_up
key_up_radio.click()
enter.click()
ActionChains(driver).key_down(Keys.SHIFT).key_up(Keys.SHIFT).perform()
print result.get_attribute('value')

# 监测key_press
key_press_radio.click()
enter.click()
ActionChains(driver).send_keys('a').perform()
print result.get_attribute('value')
driver.quit() 
复制代码

示例2:

复制代码
# -*- coding: utf-8 -*-

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from time import sleep

driver = webdriver.Firefox()
driver.implicitly_wait(10)
driver.maximize_window()

driver.get('http://sahitest.com/demo/label.htm')

input1 = driver.find_elements_by_tag_name('input')[3]
input2 = driver.find_elements_by_tag_name('input')[4]

action = ActionChains(driver)
input1.click()
action.send_keys('Test Keys').perform()
action.key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform() # ctrl+a
action.key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform() # ctrl+c

action.key_down(Keys.CONTROL, input2).send_keys('v').key_up(Keys.CONTROL).perform() # ctrl+v

print input1.get_attribute('value')
print input2.get_attribute('value')

driver.quit()
复制代码

 

五、使用示例

示例1:打开百度,搜索爬虫

复制代码
from selenium import webdriver
from time import sleep

bro = webdriver.Chrome()
bro.get(url='https://www.baidu.com/')
sleep(2)

text_input = bro.find_element_by_id('kw')
text_input.send_keys('爬虫')
sleep(2)

bro.find_element_by_id('su').click()
sleep(3)

print(bro.page_source)
bro.quit()
复制代码

示例2:获取豆瓣电影中更多电影详情数据(谷歌无头浏览器)

复制代码
from selenium import webdriver
from time import sleep
from selenium.webdriver.chrome.options import Options

第1步:下面三行固定
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')

url = 'https://movie.douban.com/typerank?type_name=%E6%83%8A%E6%82%9A&type=19&interval_id=100:90&action='

第2步:把chrome_options对象作为参数
bro = webdriver.Chrome(chrome_options=chrome_options)
bro.get(url)
sleep(3)
bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(3)
bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(3)
bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(2)
page_text = bro.page_source

with open('./douban.html','w',encoding='utf-8') as fp:
    fp.write(page_text)
print(page_text)
sleep(1)
bro.quit()
复制代码

示例3:登录qq空间

  在web 中,经常会遇到frame 嵌套页面的应用,使用WebDriver 每次只能在一个页面上识别元素,对于frame 嵌套内的页面上的元素,直接定位是定位是定位不到的。这个时候就需要通过switch_to_frame()方法将当前定位的主体切换了frame 里。先定位到iframe,再在iframe中进行标签定位。否则,定位不到我们想要的标签。

复制代码
import requests
from selenium import webdriver
from lxml import etree
import time

driver = webdriver.Chrome(executable_path=r'C:\Users\Administrator\chromedriver.exe')
driver.get('https://qzone.qq.com/')

#switch_to操作切换frame,此时才能进行登陆页面的操作。
driver.switch_to.frame('login_frame')       
#点击使用账号密码登陆,需要绑定click事件 driver.find_element_by_id('switcher_plogin').click() #driver.find_element_by_id('u').clear() driver.find_element_by_id('u').send_keys('QQ') #driver.find_element_by_id('p').clear() driver.find_element_by_id('p').send_keys('密码') #点击登陆,绑定click事件 driver.find_element_by_id('login_button').click() time.sleep(2) driver.execute_script('window.scrollTo(0,document.body.scrollHeight)') time.sleep(2) driver.execute_script('window.scrollTo(0,document.body.scrollHeight)') time.sleep(2) driver.execute_script('window.scrollTo(0,document.body.scrollHeight)') time.sleep(2) page_text = driver.page_source #获取页面源码数据,注意page_source无括号。 tree = etree.HTML(page_text) #执行解析操作 li_list = tree.xpath('//ul[@id="feed_friend_list"]/li') for li in li_list: text_list = li.xpath('.//div[@class="f-info"]//text()|.//div[@class="f-info qz_info_cut"]//text()') text = ''.join(text_list) print(text+'\n\n\n') driver.quit()
复制代码

发现小框是嵌套在大框里面的,在当前的html源码中,又嵌套了一个html子页面,这个子页面是包含在iframe标签中的。所以,如果定位的标签是存在于iframe中的,那么一定需要使用switch to函数,将当前浏览器页面的参照物切换到iframe中,iframe中有一个id为login_frame的属性值,可以根据它来定位。

示例4:利用搜狗搜索接口抓取微信公众号(无头、规避检测、等待、切换页面)

复制代码
# 添加启动参数 (add_argument)
# 添加实验性质的设置参数 (add_experimental_option)

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
import time
import requests
from lxml import etree

option = webdriver.ChromeOptions()
option.add_argument('headless')
#设置chromedriver启动参数,规避对selenium的检测机制
option.add_experimental_option('excludeSwitches', ['enable-automation'])

driver = webdriver.Chrome(chrome_options=option)

url = 'http://weixin.sogou.com/weixin?type=1&s_from=input&query=python_shequ'

driver.get(url)
print(driver.title)

timeout = 5
link = WebDriverWait(driver, timeout).until(
    lambda d: d.find_element_by_link_text('Python爱好者社区'))
link.click()
time.sleep(1)

# 切换页面
window_handles = driver.window_handles
driver.switch_to.window(window_handles[-1])
print(driver.title)

article_links = WebDriverWait(driver, timeout).until(
    # EC.presence_of_element_located((By.XPATH, '//h4[@class="weui_media_title"]'))
    lambda d: d.find_elements_by_xpath('//h4[@class="weui_media_title"]'))

article_link_list = []
for item in article_links:
    article_link = 'https://mp.weixin.qq.com' + item.get_attribute('hrefs')
    # print(article_link)
    article_link_list.append(article_link)
print(article_link_list)

first_article_link = article_link_list[0]
header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60
    }

response = requests.get(first_article_link,
                        headers=header,
                        timeout=5
                        )

tree = etree.HTML(response.text)
title = tree.xpath('//h2[@id="activity-name"]/text()')[0].strip()
content = tree.xpath('//div[@id="js_content"]//text()')
content = ''.join(content).strip()

print(title)
print(content)
复制代码

示例5:用selenium实现一个头条号的模拟发文接口

 View Code

 

示例5:用selenium实现一个头条号的模拟发文接口

复制代码
import time
import redis
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait


r = redis.Redis('127.0.0.1', 6379)

def toutiao_save_and_preview(title, content, expand_link):
    option = webdriver.ChromeOptions()
    option.add_argument('headless')
    driver = webdriver.Chrome(chrome_options=option)

    # 获取渲染的正文
    driver.get('file:///Users/Documents/toutiao.html')
    driver.execute_script("contentIn('"+ content +"');")
    timeout = 5
    content_copy = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath('//button[@class="btn"]'))
    content_copy.click()

    # 模拟登录发文页面
    cookie_toutiao = [{'name': 'ccid', 'value': 'db43e70fd9404338c49209ba04f7a11f'}, {'name': 'tt_webid', 'value': '6612748996061414925'}, {'name': 'UM_distinctid', 'value': '1667a53d28d449-0e229246a33996-4a506a-1fa400-1667a53d28e361'}, {'name': 'sso_uid_tt', 'value': '4c8179804d74252717c675607c721602'}, {'name': 'toutiao_sso_user', 'value': '8acc9b248cd201034637248021183d5a'}, {'name': 'sso_login_status', 'value': '1'}, {'name': 'sessionid', 'value': '8441fa3fc5ae5bc08c3becc780b5b2df'}, {'name': '_mp_test_key_1', 'value': '6aba81df9e257bea2a99713977f1e33b'}, {'name': 'uid_tt', 'value': '75b5b52039d4c9dd41315d061c833f0b'}, {'name': 'ccid', 'value': '4231c5cd5a98033f2e78336b1809a18a'}, {'name': 'tt_webid', 'value': '6631884089946523149'}, {'name': 'UM_distinctid', 'value': '16783e1566479-0ae7bcdcaeb592-113b6653-13c680-16783e156656d4'}, {'name': 'passport_auth_status', 'value': '99f731f2c6dc150e6dfea46799f20e90'}, {'name': 'sso_uid_tt', 'value': 'f4bcd2cf972384b428449b0479475ce6'}, {'name': 'toutiao_sso_user', 'value': '60df7bb620b4b6d1d17a1de83daec9c1'}, {'name': 'sso_login_status', 'value': '1'}, {'name': 'sessionid', 'value': '786fe64e9186d51b8427290a557b3c7b'}, {'name': 'uid_tt', 'value': '91a7a72a85861ae686fb66177bc16bca'}, {'name': '__tea_sdk__ssid', 'value': '60b289e6-e2a4-4494-a3e8-7936f9731426'}, {'name': 'uuid', 'value': 'w:3ec91cefd76b438583154fea77baa54b'}, {'name': 'tt_im_token', 'value': '1544105894108419437114683515671344747598423336731147829901779697'}]

    driver.get('https://mp.toutiao.com/profile_v3/index')
    for cookie in cookie_toutiao:
        driver.add_cookie(cookie)
    driver.get('https://mp.toutiao.com/profile_v3/graphic/publish')
    print(driver.title)

    # driver.maximize_window()
    # 写标题
    print('写标题')
    write_title = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath('//*[@id="title"]'))
    write_title.click()
    write_title.send_keys(title)

    # 粘贴正文
    print('写正文')
    write_content = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath(
        '//*[@id="graphic"]/div/div/div[2]/div[1]/div[2]/div[3]/div[2] | //div[contains(@class,"ql-editor")]'))
    write_content.click()
    write_content.clear()
    write_content.send_keys(Keys.SHIFT + Keys.INSERT)
    # time.sleep(1)

    # 检测图片上传是否完成
    try:
        if 'img' in content:
            WebDriverWait(driver, timeout).until(
                lambda d: d.find_element_by_xpath('//div[@class="pgc-img-wrapper"]'))
            print('images uploaded success')
        else:
            print('no image included')
    except:
        print('images uploaded fail')

    # 页面向下滚动
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
    time.sleep(1)

    # 添加扩展链接
    expand_check = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath(
        '//div[@class="pgc-external-link"]//input[@type="checkbox"]',
    ))
    expand_check.click()
    expand_link_box = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath(
        '//div[@class="link-input"]//input[@type="text"]',
    ))
    expand_link_box.send_keys(expand_link)
    time.sleep(1)

    # 自动封面
    front_img = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath(
        '//div[@class="article-cover"]/div/div[@class="tui2-radio-group"]/label[3]/div/input',
    ))
    front_img.click()
    time.sleep(1)

    # 保存草稿
    save_draft = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath(
        '//div[@class="publish-footer"]/button[4]/span'))
    save_draft.click()
    time.sleep(1)

    # 从内容管理页,获取预览链接和文章ID
    print('get preview_link and article_id')
    # driver.refresh()
    preview_link = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath(
        '//div[@id="article-list"]//div[@class="master-title"][1]/a')).get_attribute('href')
    article_id = preview_link.split('=')[-1]
    print(preview_link, article_id)
    time.sleep(1)


    content_management = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_link_text('内容管理'))
    content_management.click()
    time.sleep(1)
    driver.refresh()
    preview_link = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath(
        '//*[@id="article-list"]/div[2]/div/div/div[1]/div/a')).get_attribute('href')
    article_id = preview_link.split('=')[-1]

    index_page = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath('//a[@class="shead_logo"]'))
    index_page.click()
    driver.get('https://mp.toutiao.com/profile_v3/index')

    print(r.scard('cookie_pool_toutiao'))
    return preview_link, article_id


if __name__ == "__main__":
    print('start')
    start_time = time.time()
    title = 'Children'
    content = '<p>cute</p><p><img class="wscnph" src="http://img.mp.itc.cn/upload/20170105/1a7095f0c7eb4316954dda4a8b93b88c_th.jpg" /></p>'
    expand_link = 'https://www.cnblogs.com/Summer-skr--blog/'
    img = ''
    preview_link, article_id = toutiao_save_and_preview(title, content, expand_link)
    print(preview_link)
    print(article_id)
    finish_time = time.time()
print(finish_time - start_time)
复制代码

 

selenium相关文档:

         https://www.seleniumhq.org/docs/

         https://selenium-python.readthedocs.io

 

 

 

爬虫入门及selenium教程(python)

1.概论

1.1 爬虫是什么

爬虫是在网页上收集信息的程序,一般由两个部分组成,即爬取网页和解析网页。

爬虫的难点有二:1.大规模,高效率爬取 2.对动态网页或反爬机制进行针对。

1.2 爬虫的工具包(python)

爬取库:requests(基础),selenium(操作较复杂,因为模拟浏览器,具有强大的反爬和动态处理能力)

解析库:lxml(xpath),re(正则表达式),bs4(对xpath的封装改造,搜索功能较全面,但是不直接支持xpath)。 re可以对任何文本进行处理,lxml和bs4只能处理html和xml,但可以展示出网页的层级结构。

框架:scrapy,它同时集合了爬取和解析的功能,可以用于开发大型爬虫

本文将重点介绍selenium+lxml的组合

2.最简单的爬虫

用requests进行爬取,re模块进行解析。

爬取T大经管学院官网,看看它一共有多少个系(该校官网有反爬,不适合作为新手教程)

import requests
import re
resource_url = "http://www.sem.tsinghua.edu.cn/"
r = requests.get(resource_url, timeout=20)#爬取网页
data = r.content
data = data.decode('utf-8')
download_list = re.findall(r'href="/\w*/">(\w+)</a>', data)#解析网页,提取所需字段
#re.findall只捕捉分组信息,即括号内字段!

#保存数据&异常处理
if download_list:
    with open('result.txt', 'w') as f:
        for i in download_list:
            f.write('%s\n' % (i))
        print('Save as result.txt')
else:
    print('No Resource')

3.增加容错:保存原网页

在上面这段程序中,原网页数据以变量的方式储存。假如程序结束或出现异常,这些数据就会丢失,需要重新爬取。而面对反爬机制强大的网站(美团系列)时,多次重复爬取将会导致封号等严重后果。(建议多在百度这种不会封号的网站练习,再去与反爬机制较量)

另外,即使是老手也没办法保证无需debug就能准确解析所需字段,保存原网页可以节省重复爬取的时间。

在上文程序中添加以下代码,即可将原网页保存。

path='./page.txt'
with open(path,'wb') as f:
    f.write(r.content)
    f.close()

打开txt文件并解析

import re
with open(path, "r",encoding='utf-8') as f:    
    data = f.read()   
download_list = re.findall(r'href="/\w*/">(\w+)</a>', data)
print(download_list)

另外,网页也可被保存为html格式,根据爬取库和解析库来选择保存为txt还是html。下文介绍selenium+lxml的组合,使用html保存。

注1:对于初学者来说,如果没有反爬或复杂需求,可以不学习selenium。 使用requests+lxml/re/bs4或单独使用scrapy已能完成基础需求。

注2:如何看懂html是爬虫的难点,在第6点会对此进行介绍。

4.selenium入门

selenium通过创建模拟浏览器的方式进行爬取,不但可以实现登录等动态操作,而且可以规避跳转反爬。

跳转反爬:通过识别跳转行为来判断访问是否正常。requests和selenium的get方法都相当于地址栏跳转,而常规用户会从网站门页不断向里深入,selenium可以很方便地模仿这一行为。

4.1 安装selenium

参见教程:selenium 安装与 chromedriver安装 , 

太长不看版:

1.除了安装selenium包之外,还需要根据自己的浏览器安装驱动,目前selenium只支持Chrome和火狐。我安装的是Chromedriver,以下演示也是使用它。

2.假如不想配置环境变量,需要将驱动同时安装到浏览器目录和python目录下

4.2 简单实例:

在百度图片搜索"python",下滑滚动条加载更多图片,并下载前十张图

from selenium import webdriver
import time
import requests
driver = webdriver.Chrome()#声明浏览器对象
try:
    driver.get("https://image.baidu.com")#相当于地址栏跳转
    box = driver.find_element_by_id('kw')#找到输入框
    box.click() 
    box.send_keys("python")#先点一下,再输入内容
    button=driver.find_element_by_xpath("//input[@type='submit']")#找到按钮"百度一下"
    button.click - Domain Name For Sale | Dan.com()#按按钮
    time.sleep(2)#在爬虫中多用sleep,而且最好配合random,规避时间反爬(不间隔连续快速操作,有可能被识别为脚本)

    for i in range(3):
        driver.execute_script("window.scrollTo(0,document.body.scrollHeight)")#用js拖动滚动条
        time.sleep(2)

    eles=driver.find_elements_by_xpath("//li[@class='imgitem']")#找到图片们,注意这里的find_elements是复数,因此返回一个元素列表
    for i,e in enumerate(eles[:10]):
        img_data = requests.get(e.get_attribute("data-thumburl")).content#配合requests去到下载地址,用selenium需要反复跳,不方便
        img_path = 'spider_demo/'+str(i)+'.jpg'
        fp=open(img_path,'wb')
        fp.write(img_data)

    driver.close()#关闭当前标签页

except Exception as e:
    print (e)

程序运行界面如下,selenium会打开一个新的浏览器窗口


4.3 selenium基础语句

4.3.1 搜索元素

find_element_by_id

注意:在html中,为避免与js语法冲突,id唯一,因此优先考虑使用id查找元素

find_element_by_xpath

find_element_by_css_selector

熟练掌握xpath或css_selector的其中一个,在爬取和解析时,它们都能起到作用!

find_element_by_name

find_element_by_tag_name

find_element_by_class_name

4.3.2 元素

网页元素在selenium中被划为WebElement类,有以下常用属性和方法:

element.tag_name #标签名,如 'a'表示<a>元素

element.text #该元素内的文本,例如<span>hello</span>中的'hello'

element.get_attribute(x)# 该元素x属性的值

4.3.3 模拟浏览器操作

鼠标事件,可参见链接:selenium.模拟鼠标操作(ActionChains) - yonugleesin - 博客园

其中重要的鼠标事件摘录如下:

element.click()#点击

element.send_keys()#输入

ActionChains(driver).move_by_offset(xoffset,yoffset).perform()#移动鼠标,有些网页的弹窗需要我们做移开鼠标动作

ActionChains(driver).drag_and_drop_by_offset(source, xoffset, yoffset)#拖拽,多用于自动解验证码。拖滚动条用js语句更方便

其他功能

driver.get()#地址栏跳转

driver.execute_script("window.scrollTo(0,document.body.scrollHeight)")#执行js语句,这句的意思是将滚动条拖至底部

driver.switch_to.window(driver.window_handles[-1])#切换至最新标签页

4.4.4 保存页面源代码

file=open(path,'w',encoding='utf-8')
file.write(repr(driver.page_source))#repr() 函数将对象转化为供解释器读取的形式
file.close()

5.selenium的高级用法

5.1 标签页管理

selenium通过driver.switch_to.window()来切换所操作的标签页。假如一个行动打开了新的标签页,在旧页面无法继续操作新页面元素,必须先switch过去

driver.window_handles属性返回一个列表,列出目前打开的所有标签页,以时间顺序排列,故 driver.switch_to.window(driver.window_handles[-1]) 可以切换至最新标签页

driver.close()方法关闭当前标签页,driver.quit()方法关闭所有打开的标签页,假如所有标签页都被关闭,那么程序就会停止

5.1.1 锚点

一个小技巧:在遍历网页的子页时,可以将目录页保存下来,以便访问完子窗口后回到母窗口

anchor = driver.window_handles[-1]#将当前标签页设为锚点
driver.switch_to.window(anchor)#返回保存的标签页

5.2 反爬!!

5.2.1 常见反爬机制

前文已经介绍过一些,现在做一个总结

检测异常行为:如反复访问,地址栏跳转到网站深处,频繁访问等。可通过构建代理ip池以及优化爬取逻辑等规避

加密网站信息:一种加密方法是,将一些字符串转为图片,这些图片在html中会变为乱码。碰到这些,需要具体问题具体分析

检测selenium:禁止selenium等自动控制软件访问,可通过设置以及js调整

验证码:可通过设置程序自动解验证码或人工守在爬虫旁解决

检测请求头:header中的Cookie、Referer、User-Agent都是检查点,在requests中需要专门设置,selenium一般不会遇到这个问题

5.2.2 selenium反爬

通过调整浏览器选项,提供稳定运行环境并进行反爬。

一般来说,在声明浏览器前后,加上这堆东西,就不会被识别出来,此时还能威胁到我们的只剩异常访问和验证码。验证码的解决方案会在下一点中介绍,但异常访问只能靠优化爬取或者代理池来解决。

options = webdriver.ChromeOptions()
#稳定运行
options.add_argument('-enable-webgl')#解决 GL is disabled的问题
options.add_argument('--no-sandbox')  # 解决DevToolsActivePort文件不存在的报错
options.add_argument('--disable-dev-shm-usage') 
options.add_argument('--ignore-gpu-blacklist') 
options.add_argument('--allow-file-access-from-files') 

#反爬
options.add_experimental_option("excludeSwitches", ["enable-automation"])# 模拟真正浏览器
options.add_experimental_option('useAutomationExtension', False)

driver = webdriver.Chrome(options=options)#声明浏览器
#模拟真正浏览器
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
  "source": """
    Object.defineProperties(navigator,{webdriver:{get:() => false}});
  """
})

5.3 动态操作

5.3.1 滚动条到底有多长?

大家肯定见过这样的网站:它不会一次加载完所有信息,需要我们拖滚动条才能继续加载。然而,这个滚动条,到底拖多久才是个头?

我们以百度图片搜索"传承换心"为例,尝试将它的滚动条拖到底端,加载所有图片

from selenium import webdriver
import time
driver = webdriver.Chrome()#声明浏览器对象
try:
    driver.get("https://image.baidu.com")#相当于地址栏跳转
    box = driver.find_element_by_id('kw')#找到输入框
    box.click() 
    box.send_keys("传承换心")#先点一下,再输入内容
    button=driver.find_element_by_xpath("//input[@type='submit']")#找到按钮"百度一下"
    button.click - Domain Name For Sale | Dan.com()#按按钮
    
    js='window.scrollTo(0,document.body.scrollHeight)' #下滑到底部
    js2='return document.documentElement.scrollHeight' #检测当前滑动条位置

    #对于内嵌滚动条(不是网页边缘,而是网页里面可以拖动的东西),需要用getElements把这个元素找出来,再和刚才做一样的操作
    #js='document.getElementsByClassName("unifycontainer-two-wrapper")[0].scrollTop=1000000' 
    #js2='return document.getElementsByClassName("unifycontainer-two-wrapper")[0].scrollHeight'
    
    height=-1
    now=driver.execute_script(js2)
    #当滑动条位置不再被“下滑到底部”这一行为影响,说明滑动条真的到了底部
    while height!=now:
        height=now
        driver.execute_script(js)
        time.sleep(1)
        now=driver.execute_script(js2)
    
    time.sleep(5)#对于想要看结果的程序,在最后设置一下暂停
    driver.close()
    #当然,也可以直接删掉close语句,让浏览器一直开着……

except Exception as e:
    print (e)

5.3.2 验证码

验证码,据我所知有三个对策

1.使用cookie避免输入验证码

参见链接:Selenium中遇到验证码问题的处理_嘉 诚的博客-CSDN博客_selenium验证码处理

2.自动识别验证码

验证码种类多样,难以一一列举,和网站加密一样,需要具体问题具体分析

3.最为暴力的人工法

前两种方法泛用性不强,自动识别需要自己设定程序,而有些网站无视cookie,每次登陆都需要验证码。

我使用的方法是在需要输入验证码的环节设置一个time.sleep()。在time.sleep期间,我们可以对selenium打开的浏览器进行操作,比如人工输入验证码,跳转几个页面等。只要在sleep结束后,你去到的网页能够接上后续程序,就不会有任何问题。

许多大型爬虫机构依然使用人工法,因为人工法对劳动力质量和数量要求都不高。

5.4 黑科技:自动录制脚本

对于新手来说,怎么将浏览器操作转化为代码,或许还有难度。我们可以利用selenium IDE浏览器插件,录制在浏览器上的操作,并自动生成代码。

在火狐 更多工具->面向开发者的拓展 一栏可以很方便下载,但是Chrome的插件似乎需要FQ,难顶。

参考链接:自动化测试学习之路(五)-selenium IDE使用

5.5 进阶教程

这篇文章对selenium的介绍更全面详细,适合想要精益求精的大佬

Python爬虫之selenium(全套操作)常用的定位元素与常用方法_瑶山的博客-CSDN博客

6.html入门+lxml与xpath的使用

6.1 查看网页源代码

在浏览器中,随便打开一个网页,点击右键,会看见"检查"选项。点击这一项,即可查看网页源代码。假如把鼠标移动到网页的某个元素上,再选择检查,可以方便地查看到该元素在html中的位置。下图查看的是"百度一下"按钮。


6.2 很简略的html语法

在html中,尖括号<>叫做标签。标签可以成对出现,如head(标题,样式等),body(主体内容)等,也可以单个出现,如input(输入控件),img(图片)等。标签之间可以嵌套,一对标签之中可以夹着任意对标签,这构成了html的层级关系。如下图中,input就是span的子节点。

标签具有属性,以"A"=B的格式书写,说明标签有一个叫A的属性,它的值是B。如下图中,input标签的value属性值为"百度一下"。

注:html中,id属性取值唯一,也就是说id能唯一确定一个标签(假如该标签有这个属性)

关于html的详细教程,可以参考

6.3 xpath

XPath 是一门在 XML 文档中查找信息的语言,详细教程可参考

这里用例子说明一些常用语法

//img[@title]/@title

查找所有有title属性的img节点,并获取它们的title值。 //表示对当前节点以下所有节点进行搜索,/表示搜索当前节点的子节点,或用于获取属性

//img[@title='PKU']

查找所有title属性为"PKU"的img节点

//@title

查找xml中所有title属性的值。而 /@title 表示查看根节点的title属性,大部分情况下会返回空集,因为根节点无此属性

//img/img2

查找所有img节点下的img2子节点

//img/img2[1]

查找所有img节点下的第一个img2子节点,注意xpath的index不是从0而是从1开始

(//img/img2)[1]

查找所有img节点下的img2子节点,并取第一个

//img/node()

node(),模糊匹配,表示任意子节点。这句意思为查找所有img节点的所有子节点

//a/text()

查找所有a节点的内容

6.4 lxml

lxml是利用xpath查找元素的解析库。节点在lxml中被定义为Element类(和selenium的webElement相似),对于一些难以用xpath表达的复杂需求,可以先用xpath锁定该节点,再调用element类的属性和方法进行处理

关于element类的方法属性,参见官方文档:lxml.etree._Element

以下是一个简单的例子,以下为需要处理的html,节选自大众点评目录页,我们尝试把"4.54"这个数字拿出来

<div class="nebula_star">
<div class="star_icon">     
<span class="star star_45 star_sml"></span>
<span class="star star_45 star_sml"></span>
<span class="star star_45 star_sml"></span>
<span class="star star_45 star_sml"></span>
<span class="star star_45 star_sml"></span>
</div>
<div class="star_score score_45  star_score_sml">4.54</div>
</div>

 

path='demo.html'
html_text = open(path, 'r', encoding='utf-8').read()
r = html.etree.HTML(html_text)#读取html并转为etree

#方法一,直接使用xpath
scorelis=r.xpath("//div[@class='nebula_star']/div[2]/text()")

#但是在实践中,我发现有的<div class="nebula_star">中,并不是都有评分,假如按照方法一,出现缺漏,不知道是哪个漏了,因此最后选用的是以下方法
#方法二
scorelis=[]
scorenode=r.xpath("//div[@class='nebula_star']")
for s in scorenode:
    lis=s.findall("div")
    if len(lis)==1:
        scorelis.append('nan')
    else:
        scorelis.append(lis[1].text)
#这样,缺少的分数会被转化为nan

7.总结

爬虫是入门容易精通难的技术,在数据分析领域常常用到(当然,一般都是萌新负责的dirty work)。我才疏学浅,权当抛砖引玉,如有错误,还请多多指正。

8.附:美团系列字体加密破解方法

它有专门的字体包,用图片替换了部分文字,下载对应字体包即可。

参见链接:

编辑于 2021-09-08 21:54

selenium.模拟鼠标操作(ActionChains)

 

鼠标事件#

webdriver模块中的件方法:#

clear()        #清楚输入框的内容
send_keys('内容')  #在文本框内输入内容
click()        #点击按钮
submit()        #表单的提交

ActionChains模块中的方法:#

click(on_element=None)                    #单击鼠标左键

click_and_hold(on_element=None)               #点击鼠标左键,按住不放

context_click(on_element=None)               #点击鼠标右键

double_click(on_element=None)               #双击鼠标左键

drag_and_drop(source, target)               #拖拽到某个元素然后松开

drag_and_drop_by_offset(source, xoffset, yoffset)     #拖拽到某个坐标然后松开

move_by_offset(xoffset, yoffset)              #鼠标移动到距离当前位置(x,y)

move_to_element(to_element)                #鼠标移动到某个元素

move_to_element_with_offset(to_element, xoffset, yoffset) #将鼠标移动到距某个元素多少距离的位置

release(on_element=None)                  #在某个元素位置松开鼠标左键

perform()                         #执行链中的所有动作

ActionChains的两种写法:#

#首先导入模块
from selenium.webdriver.common.action_chains import ActionChains


#链条式方法
searchElement = driver.find_element_by_id('sb_form_q').send_keys('selenium')
searchButtonElement = driver.find_element_by_id('sb_form_go')
ActionChains(driver).click(searchButtonElement).perform()


#分布式方法
searchElement = driver.find_element_by_id('sb_form_q').send_keys('selenium')
searchButtonElement = driver.find_element_by_id('sb_form_go')
ActionChainsDriver = ActionChains(driver).click(searchButtonElement)
ActionChainsDriver.perform()

在12306主页做一个练习,效果如gif#

 

from selenium.webdriver.common.action_chains import ActionChains
from selenium import webdriver
from time import sleep

get_12306 = webdriver.Firefox()
get_12306.get('https://www.12306.cn/index/index.html')

g_href = get_12306.find_element_by_xpath('//*[@id="J-index"]/a')
Action = ActionChains(get_12306)


for x in range(9):
    x = x * 145
    print(x)
    Action.move_to_element_with_offset(g_href, x, 0).perform()
    sleep(0.5)

sleep(2)

get_12306.quit()
 
 
 

第01节 Selenium
1. Selenium概述
Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,Selenium 可以直接运行在浏览器上,它支持所有主流的浏览器。

因为Selenium可以控制浏览器发送请求,并获取网页数据,因此可以应用于爬虫领域。

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

Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。

官方文档:Selenium with Python — Selenium Python Bindings 2 documentation

2. 浏览器驱动
浏览器驱动用于使用selenium操控本地浏览器执行自动化操作。

驱动网站:npmmirror 中国镜像站

课程中使用Chrome浏览器作为演示工具,因此下载ChromeDriver

 

 

Figure 1:

注意需要根据本地电脑Chrome的版本选择对应的驱动包,否则无法操控浏览器

 

 

Figure 2: image-20220524105345592

 

 

Figure 3: image-20220524105418551

再根据操作系统选择不同的驱动包即可,驱动包不需要安装,只需要解压到项目目录,后续会在代码中调用。

 

 

Figure 4: image-20220524105438811

3. 基本使用
安装selenium库

 

 

Figure 5:

或使用命令

pip install selenium

控制浏览器自动网页

将驱动包导入到项目

 

 

Figure 6: image-20220524111145755

调用Chrome驱动,控制浏览器打开网页

# 导入 webdriver
from selenium import webdriver
from selenium.webdriver.common.by import By
# 调用键盘按键操作时需要引入的Keys包
from selenium.webdriver.common.keys import Keys

# 调用环境变量指定的PhantomJS浏览器创建浏览器对象
driver = webdriver.Chrome("./chromedriver.exe")
# get方法会一直等到页面被完全加载,然后才会继续程序,通常测试会在这里选择 time.sleep(2)
driver.get("http://www.baidu.com/")

控制页面元素

# id="kw"是百度搜索输入框,输入字符串"长城"
driver.find_element(By.CSS_SELECTOR,"#kw").send_keys("长城")
# id="su"是百度搜索按钮,click() 是模拟点击
driver.find_element(By.CSS_SELECTOR,"#su").click()

# 关闭浏览器
driver.quit()

第03节 常用操作
1. 元素定位
获取单个元素

driver.find_element(By.ID,"inputOriginal")
driver.find_element(By.CSS_SELECTOR,"#inputOriginal")
driver.find_element(By.TAG_NAME,"div")
driver.find_element(By.NAME,"username")
driver.find_element(By.LINK_TEXT,"下一页")

如果找不到相应的元素会报错

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: xx

获取多个元素

driver.find_elements(By.ID,"inputOriginal")
driver.find_elements(By.CSS_SELECTOR,"#inputOriginal")
driver.find_elements(By.TAG_NAME,"div")
driver.find_elements(By.NAME,"username")
driver.find_elements(By.LINK_TEXT,"下一页")

访问有道翻译网站,输入单词,并获取翻译后的内容

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome("./chromedriver.exe")
# 加载有道翻译页面
driver.get("https://fanyi.youdao.com/")
# 获取输入框
input = driver.find_element(By.ID,"inputOriginal")
# 输入内容
input.send_keys("hello")
# 获取翻译按钮
tbtn = driver.find_element(By.ID,"transMachine")
# 发现页面被遮挡,此时无法点击
# tbtn.click()

# 先获取遮挡的广告条,点击关闭按钮
close_btn = driver.find_element(By.CSS_SELECTOR,".guide-con .guide-close")
close_btn.click()

#点击翻译
tbtn.click()

#获取翻译后的内容
transTarget = driver.find_element(By.ID,"transTarget")
print(transTarget.text)

2. 内容获取
1. size 返回元素大小
2. text 获取元素的文本 <div>hello</div>
3. title 获取页面title
4. current_url 获取当前页面URL
5. get_attribute() 获取属性值 <a href="xxxx">百度</a>
6. is_display() 判断元素是否可见
7. is_enabled() 判断元素是否可用

driver = webdriver.Chrome("./chromedriver.exe")
# 加载有道翻译页面
driver.get("https://fanyi.youdao.com/")

print(driver.title)
print(driver.current_url)

# 获取输入框
transMachine = driver.find_element(By.ID,"transMachine")

print(transMachine.size)
print(transMachine.text)
print(transMachine.get_attribute("href"))
print(transMachine.is_displayed())
print(transMachine.is_enabled())

3. 窗口操作
1. maximize_window() 最大化 --> 模拟浏览器最大化按钮
2. set_window_size(100,100) 浏览器大小 --> 设置浏览器宽、高(像素点)
3. set_window_position(300,200) 浏览器位置 --> 设置浏览器位置
4. back() 后退 --> 模拟浏览器后退按钮
5. forward() 前进 --> 模拟浏览器前进按钮
6. refresh() 刷新 --> 模拟浏览器F5刷新
7. close() 关闭 --> 模拟浏览器关闭按钮(关闭单个窗口)
8. quit() 关闭 --> 关闭所有WebDriver启动的窗口

4. 元素等待
翻页获取每页元素

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome("./chromedriver.exe")
# 加载当当网
driver.get("https://www.dangdang.com/")

# 获取输入框
key = driver.find_element(By.ID,"key_S")
key.send_keys("科幻")
# 获取搜索框,点击搜索
search = driver.find_element(By.CSS_SELECTOR,".search .button")
search.click()
# 获取商品标题及价格
for i in range(5):
shoplist = driver.find_elements(By.CSS_SELECTOR, ".shoplist li")
for li in shoplist:
print(li.find_element(By.CSS_SELECTOR, "a").get_attribute("title"))
# 获取下一页按钮
next = driver.find_element(By.LINK_TEXT, "下一页")
next.click()

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

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

隐式等待是等待特定的时间,显式等待是指定某一条件直到这个条件成立时继续执行。

显式等待

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

显示等待使用WebDriverWait完成

WebDriverWait(driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None)

driver 所创建的浏览器driver
timeout 最长时间长度(默认单位:秒)
poll_frequency 间隔检测时长(每)默认0.5秒
ignored_exceptions 方法调用中忽略的异常,默认只抛出:找不到元素的异常
基础格式(webDriverWait+until+(判断条件))

until

直到调用的方法返回值为True

until(method, message=’’)

method:expected_conditions库中定义的方法
message :自定义报错信息

判断条件

判断当前页面标题是否为title title_is(title)

判断当前页面标题是否包含title title_contains(title)

判断此定位的元素是否存在,presence_of_element_located(locator)

判断页面网址中是否包含url url_contains(url)

判断此定位的元素是否可见 visibility_of_element_located(locator)

判断此元素是否可见 visibility_of(element) element:所获得的元素
判断此定位的一组元素是否至少存在一个 presence_of_all_elements_located(locator)

判断此定位的一组元素至少有一个可见,visibility_of_any_elements_located(locator)

判断此定位的一组元素全部可见visibility_of_all_elements_located(locator)

判断此定位中是否包含text_的内容,text_to_be_present_in_element(locator, text_)
locator:元素的定位信息
text_:期望的文本信息

判断此定位中的value属性中是否包含text_的内容 text_to_be_present_in_element_value(locator, text_)

locator:元素的定位信息
text_:期望的文本信息

判断定位的元素是否为frame,并直接切换到这个frame中

frame_to_be_available_and_switch_to_it(locator)

locator:元素的定位信息
判断定位的元素是否不可见 invisibility_of_element_located(locator)
locator:元素的定位信息

判断此元素是否不可见 invisibility_of_element(element)
element:所获得的元素

判断所定位的元素是否可见且可点击 element_to_be_clickable(locator)
locator:元素的定位信息

判断此元素是否不可用 staleness_of(element)
element:所获得的元素

判断该元素是否被选中 element_to_be_selected(element)
element:所获得的元素

判断定位的元素是否被选中 element_located_to_be_selected(locator)
locator:元素的定位信息

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 程序每0.5秒检查,是否满足:标题包含“百度一下”这个条件,检查是否满足条件的最长时间为:15秒,超过15秒仍未满足条件则抛出异常
WebDriverWait(driver, 15, 0.5).until(EC.title_contains("百度一下"))

# 程序每0.5秒检查,是否满足:某定位的元素出现,检查是否满足条件的最长时间为:15秒,超过15秒仍未满足条件则抛出异常
WebDriverWait(driver, 15, 0.5).until(EC.visibility_of_element_located(By.CSS_SELECTOR,"XX"))

隐式等待

隐式等待比较简单,就是设置全局元素查找的超时时间

implicitly_wait(time_to_wait)

设置的时间单位为秒,例如implicitly_wait(30),意思是超过30秒没有定位到一个元素,程序就会报错抛出异常,期间会一直轮询查找定位元素。

第04节 页面操作(动作链)
1. 鼠标及键盘操作
鼠标操作

1. context_click() 右击 --> 此方法模拟鼠标右键点击效果
2. double_click() 双击 --> 此方法模拟双标双击效果
3. drag_and_drop() 拖动 --> 此方法模拟双标拖动效果
4. move_to_element() 悬停 --> 此方法模拟鼠标悬停效果
5. perform() 执行 --> 此方法用来执行以上所有鼠标方法

driver.get("https://www.baidu.com/")
more = driver.find_element(By.LINK_TEXT,"更多")
#将鼠标移动到更多按钮
ActionChains(driver).move_to_element(more).perform()

键盘操作

1. send_keys(Keys.BACK_SPACE)删除键(BackSpace)
2. send_keys(Keys.SPACE)空格键(Space)
3. send_keys(Keys.TAB)制表键(Tab)
4. send_keys(Keys.ESCAPE)回退键(Esc)
5. send_keys(Keys.ENTER)回车键(Enter)
6. send_keys(Keys.CONTROL,'a') 全选(Ctrl+A)
7. send_keys(Keys.CONTROL,'c')复制(Ctrl+C)

from selenium.webdriver.common.keys import Keys

driver.get("https://www.baidu.com/")

element = driver.find_element(By.ID,"kw")

# 输入用户名
element.send_keys("admin1")
# 删除1
element.send_keys(Keys.BACK_SPACE)
# 全选
element.send_keys(Keys.CONTROL,'a')
# 复制
element.send_keys(Keys.CONTROL,'c')
# 粘贴
# element.send_keys(Keys.CONTROL,'v')

2. 滚动条
在HTML页面中,由于前端技术框架的原因,页面元素为动态显示,元素根据滚动条的下拉而被加载

# 1. 设置JavaScritp脚本控制滚动条,(0:左边距;1000:上边距;单位像素)
js="window.scrollTo(0,1000)"

# 2. WebDriver调用js脚本方法
driver.execute_script(js)

3. 窗口截图
自动化脚本是由程序去执行的,因此有时候打印的错误信息并不是十分明确。如果在执行出错的时候对当前窗口截图保存,那么通过图片就可以非常直观地看到出错的原因。

# 截取当前窗口
driver.get_screenshot_as_file("./demo.png")

第05节 存储数据
1. 将数据写入CSV文件
# 读写CSV文件
import csv
# 以写入方式打开文件,如果文件不存在则自动创建
f = open("d:/test.csv",'w')
# 获取csv writer,用于写入csv格式数据
writer = csv.writer(f)
# 写入数据
writer.writerow(["张三","男","1.7"])
# 关闭文件
f.close()

2. 将数据写入至MySQL
安装模块

pip install pymysql

import pymysql

# 创建连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1', charset='utf8')
# 创建游标
cursor = conn.cursor()

# 执行SQL,并返回收影响行数
effect_row = cursor.execute("select * from tb7")

# 执行SQL,并返回受影响行数
#effect_row = cursor.execute("update tb7 set pass = '123' where nid = %s", (11,))

# 执行SQL,并返回受影响行数,执行多次
#effect_row = cursor.executemany("insert into tb7(user,pass,licnese)values(%s,%s,%s)", [("u1","u1pass","11111"),("u2","u2pass","22222")])


# 提交,不然无法保存新建或者修改的数据
conn.commit()

# 关闭游标
cursor.close()
# 关闭连接
conn.close()

参考:https://www.jb51.net/article/92516.htm

注意事项
因为爬虫技术涉及面广,且技术复杂,推荐直接在网络上寻找已有数据进行处理分析,因此爬虫阶段可以只做参考。

数据网站参考:

和鲸社区:和鲸社区 - Heywhale.com
Kaggle:Find Open Datasets and Machine Learning Projects | Kaggle
GitHub:https://github.com/awesomedata/awesome-public-datasets
————————————————
版权声明:本文为CSDN博主「The Devil of hell」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

 

1. selenium爬虫
1.1 selenium概述
【1】定义
1.1) 开源的Web自动化测试工具

【2】用途
2.1) 对Web系统进行功能性测试,版本迭代时避免重复劳动
2.2) 兼容性测试(测试web程序在不同操作系统和不同浏览器中是否运行正常)
2.3) 对web系统进行大数量测试

【3】特点
3.1) 可根据指令操控浏览器
3.2) 只是工具,必须与第三方浏览器结合使用

【4】安装
4.1) Linux: sudo pip3 install selenium
4.2) Windows: python -m pip install selenium
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


1.2 PhantomJS概述
phantomjs为无界面浏览器(又称无头浏览器),在内存中进行页面加载,高效
1
1.3 环境安装
环境安装

【1】环境说明('以下三种环境任意安装其中一种即可')
环境一:selenium + PhantomJS
环境二:selenium + chromedriver + Chrome ('我们安装此版本')
环境三:selenium + geckodriver + Firefox

【2】提前下载驱动
2.1) chromedriver : 下载对应版本
http://npm.taobao.org/mirrors/chromedriver/
2.2) geckodriver
https://github.com/mozilla/geckodriver/releases
2.3) phantomjs
https://phantomjs.org/download.html

【3】添加到系统环境变量
2.1) windows: 将解压后的可执行文件拷贝到Python安装目录的Scripts目录中
windows查看python安装目录(cmd命令行):where python
2.2) Linux : 将解压后的文件拷贝到/usr/bin目录中
sudo cp chromedriver /usr/bin/

【3】Linux中需要修改权限
sudo chmod 777 /usr/bin/chromedriver

【4】验证
4.1) Ubuntu | Windows
from selenium import webdriver
webdriver.Chrome()
webdriver.Firefox()

4.2) Mac
from selenium import webdriver
webdriver.Chrome(executable_path='/Users/xxx/chromedriver')
webdriver.Firefox(executable_path='/User/xxx/geckodriver')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2. selenium详解
2.1 代码演示
"""示例代码一:使用 selenium+浏览器 打开百度"""

# 导入seleinum的webdriver接口
from selenium import webdriver
import time

# 创建浏览器对象
driver = webdriver.Chrome()
driver.get('http://www.baidu.com/')
# 5秒钟后关闭浏览器
time.sleep(5)
driver.quit()
1
2
3
4
5
6
7
8
9
10
11
12
"""示例代码二:打开百度,搜索赵丽颖,点击搜索,查看"""

from selenium import webdriver
import time

# 1.创建浏览器对象 - 已经打开了浏览器
driver = webdriver.Chrome()
# 2.输入: http://www.baidu.com/
driver.get('http://www.baidu.com/')
# 3.找到搜索框,向这个节点发送文字: 赵丽颖
driver.find_element_by_xpath('//*[@id="kw"]').send_keys('赵丽颖')
# 4.找到 百度一下 按钮,点击一下
driver.find_element_by_xpath('//*[@id="su"]').click()
1
2
3
4
5
6
7
8
9
10
11
12
13
2.2 浏览器对象方法
【1】driver.get(url=url) - 地址栏输入url地址并确认
【2】driver.quit() - 关闭浏览器
【3】driver.close() - 关闭当前页
【4】driver.page_source - HTML结构源码
【5】driver.page_source.find('字符串')
从html源码中搜索指定字符串,没有找到返回:-1,经常用于判断是否为最后一页
【6】driver.maximize_window() - 浏览器窗口最大化
1
2
3
4
5
6
7
2.3 定位节点
【1】单元素查找('结果为1个节点对象')
1.1) 【最常用】driver.find_element_by_id('id属性值')
1.2) 【最常用】driver.find_element_by_name('name属性值')
1.3) 【最常用】driver.find_element_by_class_name('class属性值')
1.4) 【最万能】driver.find_element_by_xpath('xpath表达式')
1.5) 【匹配a节点时常用】driver.find_element_by_link_text('链接文本')
1.6) 【匹配a节点时常用】driver.find_element_by_partical_link_text('部分链接文本')
1.7) 【最没用】driver.find_element_by_tag_name('标记名称')
1.8) 【较常用】driver.find_element_by_css_selector('css表达式')

【2】多元素查找('结果为[节点对象列表]')
2.1) driver.find_elements_by_id('id属性值')
2.2) driver.find_elements_by_name('name属性值')
2.3) driver.find_elements_by_class_name('class属性值')
2.4) driver.find_elements_by_xpath('xpath表达式')
2.5) driver.find_elements_by_link_text('链接文本')
2.6) driver.find_elements_by_partical_link_text('部分链接文本')
2.7) driver.find_elements_by_tag_name('标记名称')
2.8) driver.find_elements_by_css_selector('css表达式')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2.4 节点对象操作
【1】node.send_keys('') - 向文本框发送内容
【2】node.click() - 点击
【3】node.get_attribute('属性名') - 获取节点的属性值
【4】node.text - 获取当前节点及子节点和后代节点的文本内容
1
2
3
4
2.5 猫眼电影爬虫
"""
抓取猫眼电影top100的 电影名称、主演、上映时间
URL地址:https://maoyan.com/board/4
"""
from selenium import webdriver
import time

url = 'https://maoyan.com/board/4'
driver = webdriver.Chrome()
driver.get(url)

def get_data():
# 基准xpath: [<selenium xxx li at xxx>,<selenium xxx li at>]
li_list = driver.find_elements_by_xpath('//*[@id="app"]/div/div/div[1]/dl/dd')
for li in li_list:
item = {}
# info_list: ['1', '霸王别姬', '主演:张国荣', '上映时间:1993-01-01', '9.5']
info_list = li.text.split('\n')
item['number'] = info_list[0]
item['name'] = info_list[1]
item['star'] = info_list[2]
item['time'] = info_list[3]
item['score'] = info_list[4]

print(item)

while True:
get_data()
try:
driver.find_element_by_link_text('下一页').click()
time.sleep(2)
except Exception as e:
print('恭喜你!抓取结束')
driver.quit()
break
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
3. selenium高级
3.1 设置无界面模式
from selenium import webdriver

options = webdriver.ChromeOptions()
# 添加无界面参数
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
1
2
3
4
5
6
3.2 鼠标操作
"""
鼠标操作三步走:
1、创建鼠标事件类对象
2、指定鼠标行为
3、执行
"""
from selenium import webdriver
# 导入鼠标事件类
from selenium.webdriver import ActionChains

driver = webdriver.Chrome()
driver.get('http://www.baidu.com/')

# 移动到 设置,perform()是真正执行操作,必须有
element = driver.find_element_by_xpath('//*[@id="u1"]/a[8]')
ActionChains(driver).move_to_element(element).perform()

# 单击,弹出的Ajax元素,根据链接节点的文本内容查找
driver.find_element_by_link_text('高级搜索').click()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3.3 切换页面
适用网站+应对方案

【1】适用网站类型
页面中点开链接出现新的窗口,但是浏览器对象driver还是之前页面的对象,需要切换到不同的窗口进行操作

【2】应对方案 - driver.switch_to.window()

# 获取当前所有句柄(窗口)- [handle1,handle2]
all_handles = driver.window_handles
# 切换browser到新的窗口,获取新窗口的对象
driver.switch_to.window(all_handles[1])
1
2
3
4
5
6
7
8
9
民政部网站案例-selenium

"""
适用selenium+Chrome抓取民政部行政区划代码
http://www.mca.gov.cn/article/sj/xzqh/2019/
"""
from selenium import webdriver

class GovSpider(object):
def __init__(self):
# 设置无界面
options = webdriver.ChromeOptions()
options.add_argument('--headless')
# 添加参数
self.driver = webdriver.Chrome(options=options)
self.one_url = 'http://www.mca.gov.cn/article/sj/xzqh/2019/'

def get_incr_url(self):
self.driver.get(self.one_url)
# 提取最新链接节点对象并点击
self.driver.find_element_by_xpath('//td[@class="arlisttd"]/a[contains(@title,"代码")]').click()
# 切换句柄
all_handlers = self.driver.window_handles
self.driver.switch_to.window(all_handlers[1])
self.get_data()

def get_data(self):
tr_list = self.driver.find_elements_by_xpath('//tr[@height="19"]')
for tr in tr_list:
code = tr.find_element_by_xpath('./td[2]').text.strip()
name = tr.find_element_by_xpath('./td[3]').text.strip()
print(name,code)

def run(self):
self.get_incr_url()
self.driver.quit()

if __name__ == '__main__':
spider = GovSpider()
spider.run()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38


3.4 切换frame
特点+方法

【1】特点
网页中嵌套了网页,先切换到iframe,然后再执行其他操作

【2】处理步骤
2.1) 切换到要处理的Frame
2.2) 在Frame中定位页面元素并进行操作
2.3) 返回当前处理的Frame的上一级页面或主页面

【3】常用方法
3.1) 切换到frame - driver.switch_to.frame(frame节点对象)
3.2) 返回上一级 - driver.switch_to.parent_frame()
3.3) 返回主页面 - driver.switch_to.default_content()

【4】使用说明
4.1) 方法一: 默认支持id和name属性值 : switch_to.frame(id属性值|name属性值)
4.2) 方法二:
a> 先找到frame节点 : frame_node = driver.find_element_by_xpath('xxxx')
b> 在切换到frame : driver.switch_to.frame(frame_node)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
示例1 - 登录豆瓣网

"""
登录豆瓣网
"""
from selenium import webdriver
import time

# 打开豆瓣官网
driver = webdriver.Chrome()
driver.get('https://www.douban.com/')

# 切换到iframe子页面
login_frame = driver.find_element_by_xpath('//*[@id="anony-reg-new"]/div/div[1]/iframe')
driver.switch_to.frame(login_frame)

# 密码登录 + 用户名 + 密码 + 登录豆瓣
driver.find_element_by_xpath('/html/body/div[1]/div[1]/ul[1]/li[2]').click()
driver.find_element_by_xpath('//*[@id="username"]').send_keys('自己的用户名')
driver.find_element_by_xpath('//*[@id="password"]').send_keys('自己的密码')
driver.find_element_by_xpath('/html/body/div[1]/div[2]/div[1]/div[5]/a').click()
time.sleep(3)

# 点击我的豆瓣
driver.find_element_by_xpath('//*[@id="db-nav-sns"]/div/div/div[3]/ul/li[2]/a').click()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23


3.5 selenium总结
selenium+phantomjs|chrome|firefox小总结

【1】设置无界面模式
options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(excutable_path='/home/tarena/chromedriver',options=options)

【2】browser执行JS脚本
driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')

【3】鼠标操作
from selenium.webdriver import ActionChains
ActionChains(driver).move_to_element('node').perform()

【4】切换句柄 - switch_to.frame(handle)
all_handles = driver.window_handles
driver.switch_to.window(all_handles[1])

【5】iframe子页面
driver.switch_to.frame(frame_node)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
lxml中的xpath 和 selenium中的xpath的区别

【1】lxml中的xpath用法 - 推荐自己手写
div_list = p.xpath('//div[@class="abc"]/div')
item = {}
for div in div_list:
item['name'] = div.xpath('.//a/@href')[0]
item['likes'] = div.xpath('.//a/text()')[0]

【2】selenium中的xpath用法 - 推荐copy - copy xpath
div_list = browser.find_elements_by_xpath('//div[@class="abc"]/div')
item = {}
for div in div_list:
item['name'] = div.find_element_by_xpath('.//a').get_attribute('href')
item['likes'] = div.find_element_by_xpath('.//a').text
1
2
3
4
5
6
7
8
9
10
11
12
13


文章知识点与官方知识档案匹配,可进一步学习相关知识
————————————————
版权声明:本文为CSDN博主「愚人弘毅」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_49304690/article/details/112505918

 

 


原文链接:https://blog.csdn.net/weixin_51551506/article/details/127993419

 
 

posted on 2023-04-29 10:53  shuzihua  阅读(459)  评论(0编辑  收藏  举报

导航