2.爬虫之xpath选择器&selenium模块

1. xpath选择器

1.1 xpath介绍
xpath: 是一门在xml/html文档中查找信息的语句.
安装: 
pip install lxml
导入:
from lxml import etree
生成对象:

html = etree.HTML('html文档字符串')
html = etree.parse('.html文件路径', etree.HTMLParser())
1.2 选取节点表达式
查询节点:
/  : 从根节点选取 (值是一个对象)
// : 不管任何位置, 直接查找 (值是一个对象)
.  : 从当前节点
.. : 从父节点
/@属性名: 获取属性值	
/text(): 获取标签内容
1. 查找所有节点
* : 通配符表示所有
# 导入模块
from lxml import etree

# html文档字符串
doc = '''
<html>
 <head>
  <base href='http://example.com/' />
  <title>Example website</title>
 </head>
 <body>
  <div id='images'>
   <a href='image1.html' aa='bb'>Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
   <a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
   <a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
   <a href='image4.html'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
   <a href='image5.html' class='li li-item' name='items'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
   <a href='image6.html' name='items'><span><h5>test</h5></span>Name: My image 6 <br /><img src='image6_thumb.jpg' /></a>
  </div>
 </body>
</html>
'''

# 生成对象
html = etree.HTML(doc)

# 查找所有节点
node = html.xpath('//*')
print(node)

"""
[<Element html at 0x1b5918a8680>, <Element head at 0x1b5919bfb80>, ...]
"""
2. 指定节点
//标签名
# 指定节点(结果为列表)
node = html.xpath('//head')
print(node)
"""
[<Element head at 0x1ad61d0fb80>]
"""
3. 子节点
指定子标签:
1. //父标签名/子标签名
2. 标签名/child::子标签名  
# div下的a标签
# 从父节点开始找子节点
node = html.xpath('//div/a')
print(node)
# [<Element a at 0x26edb60fb00>, ...
# 指定子标签
node = html.xpath('//a[1]/child::img/@src')
print(node)
# ['image1_thumb.jpg']


# 所有子标签
node = html.xpath('//a[1]/child::*')
print(node)
# [<Element br at 0x1a0f64cfb00>, <Element img at 0x1a0f64cfb80>]
4. 子孙节点
/孙标签:
1. //祖或父标签名//子或孙标签名
1. 标签名/child::* 
# 无数据
node = html.xpath('//body/a')
print(node)  

# []

# 通过父节点找子孙节点
node = html.xpath('//body//a')
print(node)

# [<Element a at 0x26edb60fb00>, ...
# descendant:所有子孙节点
node = html.xpath('//a[6]/descendant::*')
print(node)
"""
[<Element span at 0x2826142fc80>, <Element h5 at 0x2826142fb80>, 
<Element br at 0x2826142fcc0>, <Element img at 0x2826142fd00>]
"""

# 指定子孙节点
node = html.xpath('//a[6]/descendant::h5/text()')
print(node)
# ['test']

5. 父节点
子节点/.. 找到父节点
# 父节点( a[@href="image1.html"] 查询a标签href属性值为image1.html的标签 )
node = html.xpath('//body//a[@href="image1.html"]/..')
print(node)
# [<Element div at 0x2609db50c40>]

# 索引从1开始
node = html.xpath('//body//a[1]/..')
print(node)
# [<Element div at 0x2609db50c40>]

# (parent::父标签名)

node = html.xpath('//body//a[1]/parent::div')
print(node)
# [<Element div at 0x2609db50c40>]

node = html.xpath('//body//a[1]/parent::*')
print(node)
# [<Element div at 0x2609db50c40>]

6. 祖先节点
# 获取祖先节点中的div
node = html.xpath('//a/ancestor::div')
print(node)
# [<Element html at 0x281c8e69600>, <Element body at 0x281c8f60b00>, <Element div at 0x281c8f60b80>]

# 获取所有祖先节点
node = html.xpath('//a/ancestor::*')
print(node)
# [<Element div at 0x281c8f60b80>]

7. 属性匹配
单属性值匹配:
标签名[@属性名='属性值']

多属性值匹配:
标签有class属性有多个值, 直接匹配就不可以了, 需要用contains
标签名[contains@属性名='属性值']
# 找到a标签href属性值为image1.html的标签
node = html.xpath('//body//a[@href="image1.html"]')
print(node)
# [<Element a at 0x2bb133ffbc0>]
node = html.xpath('//body//a[@class="li"]')
print(node)
# []

node = html.xpath('//body//a[contains(@class,"li")]')
print(node)
# [<Element a at 0x1a06b00fc00>]
8. 文本内容获取
标签名/text() 取当前标签的文本内容
# 文本获取
node = html.xpath('//body//a[@href="image1.html"]/text()')
print(node)  
# ['Name: My image 1 ']

node = html.xpath('//body//a/text()')
print(node)
"""
['Name: My image 1 ', 'Name: My image 2 ', 'Name: My image 3 ',
 'Name: My image 4 ', 'Name: My image 5 ', 'Name: My image 6 ']
"""
9. 属性值获取
标签名/@属性名 取当前标签的属性
标签名/attribute::* 获取所有属性值
node = html.xpath('//body//a/@href')
print(node)
# ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html', 'image6.html']

# 注意从1 开始取(不是从0)
node = html.xpath('//body//a[1]/@href')
print(node)
# ['image1.html']

node = html.xpath('//a[1]/@aa')
print(node)
# ['bb']
# attribute::* 获取所有属性值
node = html.xpath('//a[1]/attribute::*')
print(node)  
# ['image1.html', 'bb']
10. 按序选择
正序:
标签名[序号]      序号从1开始

倒序:
标签名[last()]    最后一个
标签名[last()-n]  倒数第n+1
node = html.xpath('//a[2]/text()')
print(node)
# ['Name: My image 2 ']

node = html.xpath('//a[2]/@href')
print(node)
# ['image2.html']

# 倒数最后一个
node = html.xpath('//a[last()]/@href')
print(node)
# ['image6.html']

# 倒数第二个
node = html.xpath('//a[last()-1]/@href')
print(node)

11. 位置条件
标签名[position()<序号]
# 位置小于3的
node = html.xpath('//a[position()<3]/@href')
print(node)
# ['image1.html', 'image2.html']

12. 同级节点查找
/following:当前节点之后所有同级节点(包括同级节点的子孙节点)
following-sibling:当前节点之后同级节点(只找兄弟)
# a标签的所有同级标签(所有标签)
node = html.xpath('//a[3]/following-sibling::*')
print(node)
# [<Element a at 0x1ea35420b40>, <Element a at 0x1ea35420a40>, <Element a at 0x1ea35420b80>]

# a标签的所有同级标签(指定某个标签)
node = html.xpath('//a[3]/following-sibling::a')
print(node)
# [<Element a at 0x1ea35420b40>, <Element a at 0x1ea35420a40>, <Element a at 0x1ea35420b80>]

# a标签的所有同级标签(所有标签, 取第二个)
node = html.xpath('//a[1]/following-sibling::*[2]')
print(node)
# [<Element a at 0x1ea35420bc0>]

node = html.xpath('//a[1]/following-sibling::*[2]/@href')
print(node)
# ['image3.html']
1.3 复制xpath路径

2022-06-28_171346

xpath路径: //*[@id="hotsearch-content-wrapper"]/li[1]/a/span[2]
完整xpath路径: /html/body/div[1]/div[1]/div[5]/div/div/div[3]/ul/li[1]/a/span[2]

2. Web应用测试工具

selenium: 是一个用于Web应用程序测试的工具.

使用requests速度快, 可以开启多线程, requests无法直接执行JavaScript代码.
爬虫中使用是为了解决requests无法直接执行JavaScript代码的问题, 但是速度慢.
2.1 安装selenium
安装selenium: pip3 install selenium==3.141.0
最新版本好多方法弃用了...
2.2 下载驱动
谷歌浏览器驱动网址: http://npm.taobao.org/mirrors/chromedriver/
* 1. 找到chrome版本信息

2022-06-28_173725

* 2. 下载对应版本的驱动(驱动器版本向下兼容)

2022-06-28_173920

2022-06-28_173955

* 3. 下载之后解压得到一个可执行文件(不需要安装)

2022-06-28_174417

2.3 等待元素加载
网页加载需要一定的时间, 通过代码去查找标签速度非常快, 可能标签还没加载完, 代码就查找了, 
如果找不到会报错.
在执行代码查找标签之前先等待标签加载完毕.
两种方式:
1. 显示等待: 每个标签都要写等待逻辑.
2. 隐式等待: 写一个逻辑, 所有标签遵循这个规则.
   元素对象.implicitly_wait(等待加载时间)  超时报错
from selenium import webdriver

bro=webdriver.Chrome(executable_path='./chromedriver.exe')

# 在地址栏输入地址
bro.get('https://www.jd.com/')
bro.implicitly_wait(10)

...
2.4 简单使用
生成对象:
浏览器对象 = webdriver.Chrome(executable_path='驱动器路径') 

打开网页: 
浏览器对象.get('网络地址')

打印文本信息:
浏览器对象.page_source

关闭当前页面:
浏览器对象.close()

退出浏览器:
浏览器对象.quit()  
# 导入网络驱动程序模块
from selenium import webdriver

# 得到一个谷歌浏览器对象(打开一个浏览器窗口)
bro = webdriver.Chrome(executable_path='./chromedriver.exe')  # 指定使用的驱动

# 在地址栏里输入了访问地址
bro.get('https://www.baidu.com/')

# 打印网页文本信息
print(bro.page_source)

# 关闭浏览器
bro.close()

2.5 查找标签
 (最新版本模块很多方法被弃用!)
# ===============find系列方法查找元素===================
不带s:
1. find_element_by_id                  通过id查找
2. find_element_by_link_text           通过a标签的文本内容找
3. find_element_by_partial_link_text   通过a标签的文本内容找, 模糊匹配
4. find_element_by_tag_name            标签名
5. find_element_by_class_name          类名
6. find_element_by_name                name属性
7. find_element_by_css_selector        通过css选择器
8. find_element_by_xpath               通过xpaht选择器
带s:
强调:find_elements_by_xxx的形式是查找到多个元素, 结果为列表

元素对象.send_keys('搜索关键字') 往控件中写入搜索关键字
元素对象.clear() 清空输入的内容
元素对象.click() 点击按钮
元素对象.get_attribute('属性名') 获取元素的属性
元素对象.text 获取元素的文本信息

css选择器的复制方法:
#app > div > div > div > div.el-col.el-col-24 > section > div > 
div.scroll_main.el-scrollbar__wrap.el-scrollbar__wrap--hidden-default > div

2022-06-29_103906

1. 自动搜索案例
* 1. 找到输入框

2022-06-28_204641

* 2. 找到搜索按键

2022-06-28_204744

from selenium import webdriver


# 用代码打开一个浏览器

bro = webdriver.Chrome(executable_path='chromedriver.exe')  # win

# 在地址栏输入地址
bro.get('https://www.so.com/')

# 找到输入框
search = bro.find_element_by_id('input')
# 在输入框输入美女
search.send_keys("美女")

# 找到搜索按钮
button = bro.find_element_by_id('search-button')
# 点击一下按钮
button.click()


print(bro.page_source)  # 当前页面的html内容
# 将页面缓存
with open('baidu.html', 'w', encoding='utf-8') as f:
    f.write(bro.page_source)  # 包含redner+ajax

bro.close()

GIF 2022-6-28 20-50-24

2.自动登入案例
全自定登入越来越难. 必要的时候验证手动验证.
* 1. 找到登入按键

2022-06-29_103730

* 2. 找打账户登入

2022-06-29_104106

* 3. 找到用户名与密码输入框

2022-06-29_104224

* 4. 找打登入按键

2022-06-29_104339

* 5. 登入代码(验证码手动)
from selenium import webdriver
import time

bro = webdriver.Chrome(executable_path='./chromedriver.exe')

# 在地址栏输入地址
bro.get('https://www.baidu.com/')
bro.implicitly_wait(10)
# 获取页面登入按键
user_login = bro.find_element_by_id('s-top-loginbtn')
# 点击登入
user_login.click()

# # 找到账户登入
account_login = bro.find_element_by_id('TANGRAM__PSP_11__changePwdCodeItem')
# # 点击账户登入
account_login.click()

# 找到账户密码输入框并输入信息
username = bro.find_element_by_id('TANGRAM__PSP_11__userName')
username.send_keys('1360012768@qq.com')

password = bro.find_element_by_id('TANGRAM__PSP_11__password')
password.send_keys('1314.qqq')

# 获取登入按键
button = bro.find_element_by_id('TANGRAM__PSP_11__submit')
button.click()

time.sleep(10)

bro.close()

GIF 2022-6-29 13-27-12

2.6 无界面浏览器
selenium必须是打开浏览窗口, 爬虫不需要展示窗口, 则设置为无界面浏览器.
from selenium import webdriver

from selenium.webdriver.chrome.options import Options

# 得到一个配置对象
chrome_options = Options()
chrome_options.add_argument('window-size=1920x3000')  # 指定浏览器分辨率
chrome_options.add_argument('--disable-gpu')  # 谷歌文档提到需要加上这个属性来规避bug
chrome_options.add_argument('--hide-scrollbars')  # 隐藏滚动条, 应对一些特殊页面
chrome_options.add_argument('blinfk-settings=imagesEnabled=alse')  # 不加载图片, 提升速度
chrome_options.add_argument('--headless')  # 浏览器不提供可视化页面. 
# linux下如果系统不支持可视化不加这条会启动失败

# 设置配置
bro = webdriver.Chrome(executable_path='./chromedriver.exe', options=chrome_options)

bro.get('https://www.baidu.com')
print(bro.page_source)
2.7 pillow扣图
安装pillow模块: pip install pillow
元素对象.save_screenshot('保存路径')   把整个页面保存成图片
元素对象.location 元素的左上角坐标.
元素对象.size 元素占用的大小
元素对象.id  元素id(selenium分配的)
元素对象.tag_name (元素的名称)
from selenium import webdriver
from PIL import Image

bro = webdriver.Chrome(executable_path='./chromedriver.exe')

# 在地址栏输入地址
bro.get('https://www.jd.com/')

# 找到图片
img = bro.find_element_by_css_selector('a.logo_tit_lk')
print(img.location)  # 图片位置 {'x': 105, 'y': 41}
print(img.size)  # 图片大小  通过位置和大小可以唯一确定这张图,通过截图可以把图截出来
# {'height': 120, 'width': 190}
print(img.id)  # selenium提供的id号,忽略
print(img.tag_name)  # a

location = img.location
size = img.size
bro.save_screenshot('./main.png')  # 把整个页面保存成图片
# 补充:标签位置和大小:size和location
# pillow抠图,把图标抠出来
# 第一个参数 开始截图的x坐标
# 第二个参数 开始截图的y坐标
# 第三个参数 结束截图的x坐标
# 第四个参数 结束截图的y坐标
img_tu = (
    # 105 41 105+120 41+190
    int(location['x']), int(location['y']), int(location['x'] + size['width']), int(location['y'] + size['height']))
# #使用pillow打开截图
img = Image.open('./main.png')
# 从截图中按照位置扣除验证码
code_img = img.crop(img_tu)
# 把扣出来的图,保存到本地
code_img.save('./code.png')

bro.close()

# 一般用来扣验证码图片:可能会由于分辨率问题导致扣出的图不一致---》通过修改分辨率--》实现正确抠图
# 验证码是img---》src--》自己加载就能拿到验证码,保存到本地即可(requests)-->更简单

2.8 执行js
浏览器对象.execute_scripr('js代码')

常用操作: 
1. 执行js代码
2. 使用页面的变量和函数
1. alert弹框
# alert弹框
from selenium import webdriver
import time

bro = webdriver.Chrome(executable_path='./chromedriver.exe')

# 在地址栏输入地址
bro.get('https://www.csdn.net/')
bro.execute_script("alert('hello')")

time.sleep(3)
bro.switch_to.alert.accept()  # 需要关闭alert弹窗不然会报错
bro.close()
2. 滑动页面
垂直滑动 window.scrollBy(起始坐标, 结束坐标)
document.body.scrollHeight 获取页面的高度
# 滑动页面
from selenium import webdriver
import time

bro = webdriver.Chrome(executable_path='./chromedriver.exe')

# 在地址栏输入地址
bro.get('https://www.csdn.net/')
# 向下滑动500px
bro.execute_script("window.scrollBy(0, 500)")
time.sleep(2)

# 滑动底部
bro.execute_script("window.scrollBy(0, document.body.scrollHeight )")
time.sleep(2)

bro.close()

3. 使用变量
使用页面中定义的表量

2022-06-29_144254

from selenium import webdriver

bro = webdriver.Chrome(executable_path='./chromedriver.exe')

# 在地址栏输入地址
bro.get('https://www.baidu.com')
bro.execute_script('console.log(bds)')

2022-06-29_144611

2.9 选项卡操作
选项卡-->新开网页
新开选项卡: window.open() 
获取虽有选项卡: 浏览器对象.window_handles 
切换选项卡: 浏览器对象..switch_to.window(选项卡)
from selenium import webdriver

bro = webdriver.Chrome(executable_path='./chromedriver.exe')

# 在地址栏输入地址
bro.get('https://www.baidu.com')

# 新开选项卡
bro.execute_script('window.open()')

# 获取所有选项卡  值是一个列表 [选项卡1, 选项卡2, ...]
all_window = bro.window_handles

# 切换到第一个选项卡 打开博客园
bro.switch_to.window(all_window[0])
bro.get('https://www.cnblogs.com/')

# 切换到第二个选项卡 打开csnd
bro.switch_to.window(all_window[1])
bro.get('https://www.csdn.net/')

bro.close()  # 关闭第二个选项卡
bro.quit()  # 退出浏览器

2.10 页面前进后退
后退: 浏览器对象.back()
前进: 浏览器对象.forward()
from selenium import webdriver
import time
bro = webdriver.Chrome(executable_path='./chromedriver.exe')

# 在地址栏输入地址
bro.get('https://www.baidu.com')
bro.get('https://www.taobao.com')
bro.get('https://www.bilibili.com/')
time.sleep(1)

# 后退到淘宝
bro.back()
time.sleep(1)

# 后退到百度
bro.back()
time.sleep(1)

# 前进到淘宝
bro.forward()
time.sleep(1)

# 前进到哔哩哔哩弹幕网
bro.forward()
time.sleep(1)


# 退出浏览器
bro.quit()
2.11 异常处理
from selenium import webdriver
bro = webdriver.Chrome(executable_path='./chromedriver.exe')

# 在地址栏输入地址
try:
    bro.get('https://www.baidu.com')
    bro.find_element_by_id('xxxx')

except Exception as e:
    print(f'程序出错: {e}')
    bro.quit()
2.12 半自动登入博客园
操作步骤:
    1. 先半自动登入到博客园
    2. 将cookice保存到本地
    3. 携带cookice访问博客园
* 1. 获取登入标签

2022-07-06_142633

* 2. 获取账户密码表单按钮

2022-07-06_143146

* 3. 获取账户密码登入标签

2022-07-06_143314

* 4. 半自动登入获取cookie保存到本地
from selenium import webdriver
bro = webdriver.Chrome(executable_path='./chromedriver.exe')

# 在地址栏输入地址
try:
    bro.get('https://www.cnblogs.com/')
    # 隐式等待
    bro.implicitly_wait(10)
    # 获取登入按钮
    login_button = bro.find_element_by_link_text('登录')
    # 点击登入
    login_button.click()
    
    # 获取密码登入标签
    password_button = bro.find_element_by_class_name('mat-tab-label-content')
    password_button.click()

    # 获取账户框
    username_input = bro.find_element_by_id('mat-input-0')
    # 输入账户名
    username_input.send_keys('你的账户')

    # 获取密码框
    password_input = bro.find_element_by_id('mat-input-1')
    # 输入密码
    password_input.send_keys('你的密码')

    # 获取登入按键
    button = bro.find_element_by_class_name('mat-button-wrapper')
    # 点击登入
    button.click()

    # 手动操作验证码, 程序停止在这里, 按下任意按键往下走
    input()

    # 将cookie保存到问文件中
    import json
    with open('cookie.json', mode='w') as wf:
        # get_cookies() 获取cookie 值是一个列表套字典
        json.dump(bro.get_cookies(), wf)

except Exception as e:
    print(f'程序出错: {e}')

finally:
    bro.quit()

GIF 2022-7-6 15-07-06

* 5. cookie信息
[
    {
        "domain":"www.cnblogs.com",
        "httpOnly":true,
        "name":".AspNetCore.Antiforgery.b8-pDmTq1XM",
        "path":"/",
        "secure":false,
        "value":"CfDJ8EOBBtWq0dNFoDS-ZHPSe53mEWd-ZGyjWftpCaA67Ju_PAmyKJdgIMJ6TQroItTC3KugfG1kyhlNdZx9twkZXOMpcOw8OMkPl0v3uajxTJTOJKtxX4sy1Az7e2VbFXcrcgff2l2J1QRpKn75hQ0ldtYSAD"
    },
    {
        "domain":".cnblogs.com",
        "expiry":1720163214,
        "httpOnly":false,
        "name":"_ga",
        "path":"/",
        "secure":false,
        "value":"GA1.2.1702123200.1657091158"
    },
    {
        "domain":".cnblogs.com",
        "httpOnly":true,
        "name":".CNBlogsCookie",
        "path":"/",
        "secure":false,
        "value":"6AE367FDC883C9497C0965F5DCB0773D77C7B6E04AC8D3483B085CC7C8C7FD46E080F1CFF9028730A81B4781393E850814E684ABDFA2FFD7D01C0CAEB96C28EA39E26578AFF0E5355617C5C2A5191DB59937CC937D"
    },
    {
        "domain":".cnblogs.com",
        "expiry":1690787158,
        "httpOnly":false,
        "name":"__gpi",
        "path":"/",
        "secure":false,
        "value":"UID=00000769a61d749c:T=1657091158:RT=1657091158:S=ALNI_MYpovhSSJNIllzFre6jRxKvDbXmXA"
    },
    {
        "domain":".cnblogs.com",
        "expiry":1690787158,
        "httpOnly":false,
        "name":"__gads",
        "path":"/",
        "secure":false,
        "value":"ID=614211f6e18ef14e:T=1657091158:S=ALNI_MabIFcMdHavfJFTtGjdvxUNM6oWJA"
    },
    {
        "domain":".cnblogs.com",
        "expiry":1657177614,
        "httpOnly":false,
        "name":"_gid",
        "path":"/",
        "secure":false,
        "value":"GA1.2.2027133757.1657091158"
    },
    {
        "domain":".cnblogs.com",
        "httpOnly":true,
        "name":".Cnblogs.AspNetCore.Cookies",
        "path":"/",
        "secure":false,
        "value":"CfDJ8EOBBtWq0dNFoDS-ZHPSe50ngXRAr8WvkjMPVK2CErFjHpfDDCUA5wWx_coJ_pBtFO5I5aDCaZKVAU3ENMhSzukVskoTcTgvCsxz6lBceGIdIGBAjpxkahkqzDHb323TpdV2X3KMcJUTH-Fzz5NDhvMzDBfrcgOuvhUiu67tqzJeweta9Ld_qo2d7zGzHcCQOhVZJAXsZYB6lERqnNx83pRWzwUbmeoxPjvpQiILl6Amab0RkkoGS4wP5K1l0_gn1XBdke5Vp2fXqVIAJoIpV12PC2AjcrV2ABKdYMts_qAZ6UrhK_Rk7cc8wrvyNPP63dvg8pqsceIPl45GS0XuqfPLg1K9nCydFp426a-2UUix2pIwyxKDsq3IpP6qgq4QlkzfZm9CvgF7Tq-14s4327l9uCJEYmrNyeghaBM-4WhHabI_FD6K-xweqaFVx_n5aN5vhXV9yFRiUOFD71kn5FcwOhnImFKDHnmRUaSSy4AyhawQ8hT6UTQcXcigkDStc4wkz-jXpsDdYYxED3fZAp9IwLQv63U9mEG51LlyM7jQ8"
    },
    {
        "domain":".cnblogs.com",
        "httpOnly":false,
        "name":"Hm_lpvt_866c9be12d4a814454792b1fd0fed295",
        "path":"/",
        "secure":false,
        "value":"1657091215"
    },
    {
        "domain":".cnblogs.com",
        "expiry":1720163214,
        "httpOnly":false,
        "name":"_ga_3Q0DVSGN10",
        "path":"/",
        "secure":false,
        "value":"GS1.1.1657091159.1.1.1657091214.5"
    },
    {
        "domain":".cnblogs.com",
        "expiry":1688627214,
        "httpOnly":false,
        "name":"Hm_lvt_866c9be12d4a814454792b1fd0fed295",
        "path":"/",
        "secure":false,
        "value":"1657091158"
    }
]
* 6. 携带cookie访问博客园
from selenium import webdriver
bro = webdriver.Chrome(executable_path='./chromedriver.exe')

# 在地址栏输入地址
try:
    # 访问博客园
    bro.get('https://www.cnblogs.com/')

    # 读取cookie
    with open('cookie.json', mode='r', encoding='utf8') as rf:
        import json
        cookie = json.load(rf)

    # 浏览器对象添加cookie [{}, {}, ..]
    for item in cookie:
        # 将所有的cookie字典逐个添加
        bro.add_cookie(item)

    # 刷新页面
    bro.refresh()

    import time
    time.sleep(3)

except Exception as e:
    print(f'程序出错: {e}')

finally:
    bro.quit()

GIF 2022-7-6 15-20-42

2.13 抽屉新闻自动点赞
操作步骤:
1. 使用selenium半自动登入到抽屉新闻网, 获取到cookie.
2. 使用request携带cookie访问抽屉新闻网, 批量点赞文章.
* 1. 获取登入按键

2022-07-06_172842

* 2. 获取到手机号码登入

2022-07-06_172927

* 3. 获取到手机号输入输入框, 密码输入框, 登入按钮

2022-07-06_173104

* 4. 自动登入代码
from selenium import webdriver

bro = webdriver.Chrome(executable_path='./chromedriver.exe')

# 在地址栏输入地址
try:
    # 访问抽屉新闻
    bro.get('https://dig.chouti.com/')
    # 隐式等待
    bro.implicitly_wait(10)

    # 获取登入按键
    login_button = bro.find_element_by_id('login_btn')

    # login_button.click()
    # 点击会报错 Message: element click intercepted 消息:元素点击被拦截

    # 使用js操作点击
    bro.execute_script('arguments[0].click()', login_button)

    # 获取手机号码登入选择标签
    phone_login = bro.find_element_by_link_text('手机号登录')
    phone_login.click()

    # 获取手机号码输入框
    phone_input = bro.find_element_by_name('phone')
    phone_input.send_keys('账户')

    import time

    time.sleep(2)

    # 获取密码输入款
    password_input = bro.find_element_by_name('password')
    password_input.send_keys('密码')

    import time

    time.sleep(2)

    # 获取登入按键
    button_btn = password_input = bro.find_element_by_name('password')
    button_btn.click()
	
    input()  # 手动验证.
    
    
    # 获取cookie 保存到本地
    with open('chouti_cookie.json', mode='w') as wf:
        import json

        json.dump(bro.get_cookies(), wf)

except Exception as e:
    print(f'程序出错: {e}')

finally:
    bro.quit()

* 5. 获取到cookie
[
    {
        "domain":"dig.chouti.com",
        "expiry":2147483647,
        "httpOnly":false,
        "name":"YD00000980905869%3AWM_NI",
        "path":"/",
        "secure":false,
        "value":"hVmgjDuEehm%2F6tUcue5fPsyZBX4g%2BiVrsda5Y2A%2BAlPh5Q9JvDwOUT75TtZvqQSBAJT0GPwQDrndVOoDV6BF%2FM2FysGrBvko6XTGutmHh5yXaXVnRwGhFNF6B0E2IN3UpudUlU%3D"
    },
    {
        "domain":"dig.chouti.com",
        "expiry":1814786532,
        "httpOnly":false,
        "name":"_9755xjdesxxd_",
        "path":"/",
        "secure":false,
        "value":"32"
    },
    {
        "domain":"dig.chouti.com",
        "expiry":1814786532,
        "httpOnly":false,
        "name":"gdxidpyhxdE",
        "path":"/",
        "secure":false,
        "value":"XUz83Gg7sk4v6wKgX6oScjyLZD7IOVNSrpWzlqERCDA2o1hH1BbZYPc58ewHkCKaUMqoZyHX%2BNtoujYBmJlLnvPj1cg6yK2nlPDJDbWKGZo%2FICGr%5CLmiL2ZHNV9lEvGjnRsa%2B%5CArVE1PLTD7%2FnAD7Jbrm%2BKBV7V0IIg6eR%5CLUeRseNE6x6%3A1657106532758"
    },
    {
        "domain":"dig.chouti.com",
        "expiry":2147483647,
        "httpOnly":false,
        "name":"YD00000980905869%3AWM_TID",
        "path":"/",
        "secure":false,
        "value":"wLMI2HmPOO5FVVQAQBfUBrdKG0JzBhyT"
    },
    {
        "domain":"dig.chouti.com",
        "expiry":1688641631,
        "httpOnly":false,
        "name":"__snaker__id",
        "path":"/",
        "secure":false,
        "value":"akew1JdgZb6KMz9y"
    },
    {
        "domain":".chouti.com",
        "httpOnly":false,
        "name":"Hm_lpvt_03b2668f8e8699e91d479d62bc7630f1",
        "path":"/",
        "secure":false,
        "value":"1657105631"
    },
    {
        "domain":".chouti.com",
        "expiry":1688641631,
        "httpOnly":false,
        "name":"Hm_lvt_03b2668f8e8699e91d479d62bc7630f1",
        "path":"/",
        "secure":false,
        "value":"1657105631"
    },
    {
        "domain":"dig.chouti.com",
        "expiry":2147483647,
        "httpOnly":false,
        "name":"YD00000980905869%3AWM_NIKE",
        "path":"/",
        "secure":false,
        "value":"9ca17ae2e6ffcda170e2e6eed6e868fbf18dd8c569b4a88ba3c44e979b9facd55eedbc81a8b443ae9fa4d4d22af0fea7c3b92aac8aa388e950b79bab89f025f6ac9b84f86ff7baa094fc528288fc88aa6396aefbbab14be99fa4b1eb3f93e78697c77d8d8b9cd8b860b886ba92d4598sa29f86b5b34d94a99fa5f166a88a8190c75ef69e8ad0d03a86a7bda8f14ab6b5a1d7db6085abbc8ecb64f7a79882db5eae8eb9a8eb4e8e9afaa3b34ff29782d4d87cb7bc9b8dd837e2a3"
    },
    {
        "domain":"dig.chouti.com",
        "expiry":1688641630,
        "httpOnly":false,
        "name":"deviceId",
        "path":"/",
        "secure":false,
        "value":"web.eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqaWQisaOiI5ZmY2Nzk5Yy04NTdlLTQ3MGYtOGMzYS0yMTY1ZTE3MDBkZGMiLCJleHBpcmUiOiIxNjU5Njk3NjMwNDQzIn0.ZxRk1tBgdJ4EZraM_AnGOxvKNl6Mgv1x7FJqCfklTTg"
    }
]
* 注意!!!

2022-07-06_170245

* 6. 点赞请求地址
发送请求地址: https://dig.chouti.com/link/vote

2022-07-06_175940

* 7. 点赞携带数据: linkId: 文章id
文章id 在div标签  div标签a标签的data-id属性中

2022-07-06_180023

2022-07-06_180929

* 8. 点赞成功之后返回响应

2022-07-06_183802

* 9. request访问抽屉网 获取所有文章div标签节点

2022-07-06_174755

import requests
from bs4 import BeautifulSoup
header = {

    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36'
}
res=requests.get('https://dig.chouti.com/',headers=header)
# print(res.text)
soup=BeautifulSoup(res.text,'lxml')
div_list=soup.find_all(class_='link-item')
for div in div_list:
    article_id=div.attrs.get('data-id')
    print(article_id)
    if article_id:
        data = {
            'linkId': article_id
        }
        # cookie 写入
        cookie={}
        with open('chouti.json', 'r') as f: 
            import json
            res = json.load(f)
        for item in res:
            # selenium的cookie和requests模块使用的cookie不太一样,requests只要name和value
            cookie[item['name']] = item['value']
        res = requests.post('https://dig.chouti.com/link/vote', headers=header, data=data,cookies=cookie)
        print(res.text)

2022-07-06_190816

2.14 京东商品信息
* 1. 获取到搜索框

* 2. 获取搜索按键 或者使用 回车按键

2022-07-09_130425

* 3. 获取商品信息

2022-07-09_131202

* 获取图片就有一直出问题, 图片链接后缀一会是.jpg, 
一会是.jpg.avif 只能拿到前四个商品的图片, 之后的都是None.
img的src数值值放在了data-lazy-img属性中
from selenium import webdriver
# 导入按键模块
from selenium.webdriver.common.keys import Keys

bro = webdriver.Chrome(executable_path='./chromedriver.exe')


def get_commodity(bro):
    # 获取商品信息
    li_list = bro.find_elements_by_class_name('gl-item')

    # 遍历商品列表
    for commodity in li_list:
        # 跳过广告, 广告的排版不一样 以下获取商品信息操作会出错
        try:
            # 商品名称 通过css类选择器查找
            name = commodity.find_element_by_css_selector('.p-name em').text
            # 商品价格
            price = commodity.find_element_by_css_selector('.p-price i').text
            # 商品链接
            url = commodity.find_element_by_css_selector('.p-img a').get_attribute('href')
            # 商品评论数
            commit = commodity.find_element_by_css_selector('.p-commit a').text

            img = commodity.find_element_by_css_selector('.p-img img').get_attribute('src')
            # img的src属性没有值则从data-lazy-img属性中取
            if not img:
                img = 'https:' + commodity.find_element_by_css_selector('.p-img img').get_attribute('data-lazy-img')

            # 去除.avif后缀
            img = img.strip('.avif')

            print(f"""
    商品名称: {name}
    商品价格: {price}
    商品链接: {url}
    商品图片: {img}
    商品评论数: {commit}
    
    """)
        except Exception:
            continue

    # 获取下一页
    next_button = bro.find_element_by_class_name('pn-next')
    import time
    time.sleep(2)
    next_button.click()

    # 递归执行, 报错则停
    get_commodity(bro)


try:
    # 爬取京东商品信息
    bro.get('https://www.jd.com/')
    # 隐式等待
    bro.implicitly_wait(10)

    # 获取搜索框
    search_input = bro.find_element_by_id('key')
    # 搜索商品
    search_input.send_keys('Python')

    # 通过回车按键搜索
    search_input.send_keys(Keys.ENTER)

    # 获取数据
    get_commodity(bro)

except Exception as e:
    print(f'出现异常: {e}')

finally:
    bro.quit()

结果:
商品名称: 零基础学Python(Python3.9全彩版)(编程入门 项目实践 同步视频)
商品价格: 69.40
商品链接: https://item.jd.com/12353915.html
商品图片: https://img10.360buyimg.com/n1/s200x200_jfs/t1/192162/30/9469/137831/60cff716E24a6f3a9/f11a344fb18010fc.jpg
商品评论数: 20+
...
2.15 动作链
from selenium import webdriver
import time
# pillow
from PIL import Image

# 引入超级鹰

from chaojiying import Chaojiying_Client
# 导入动作链
from selenium.webdriver import ActionChains

# 生成对象
bro=webdriver.Chrome(executable_path='./chromedriver.exe')
# 隐式等待
bro.implicitly_wait(10)

try:
    bro.get('https://kyfw.12306.cn/otn/resources/login.html')
    bro.maximize_window()  # 窗口最大化,全屏
    # 获取到图片验证码位置
    button_z=bro.find_element_by_css_selector('.login-hd-account a')
    button_z.click()
    time.sleep(2)
    # 截取整个屏幕
    bro.save_screenshot('./main.png')
    # 验证码的位置和大小
    img_t=bro.find_element_by_id('J-loginImg')
    print(img_t.size)
    print(img_t.location)

    size=img_t.size
    location=img_t.location

    img_tu = (int(location['x']), int(location['y']), int(location['x'] + size['width']), int(location['y'] + size['height']))
    # 抠出验证码
    # 打开
    img = Image.open('./main.png')
    # 抠图
    fram = img.crop(img_tu)
    # 截出来的小图
    fram.save('code.png')

    # 调用超级鹰破解
    chaojiying = Chaojiying_Client('用户名', '密码', '903641')	

    im = open('code.png', 'rb').read()													
    # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//


    # 返回结果如果有多个 260,133|123,233,处理这种格式[[260,133],[123,233]]
    res=chaojiying.PostPic(im, 9004)
    print(res)
    result=res['pic_str']

    all_list = []
    if '|' in result:
        list_1 = result.split('|')
        count_1 = len(list_1)
        for i in range(count_1):
            xy_list = []
            x = int(list_1[i].split(',')[0])
            y = int(list_1[i].split(',')[1])
            xy_list.append(x)
            xy_list.append(y)
            all_list.append(xy_list)
    else:
        x = int(result.split(',')[0])
        y = int(result.split(',')[1])
        xy_list = []
        xy_list.append(x)
        xy_list.append(y)
        all_list.append(xy_list)
    print(all_list)
    # 用动作链,点击图片
    # [[260,133],[123,233]]
    for a in all_list:
        x = a[0]
        y = a[1]
        ActionChains(bro).move_to_element_with_offset(img_t, x, y).click().perform()
        time.sleep(1)

    username=bro.find_element_by_id('J-userName')
    username.send_keys('账户')
    password=bro.find_element_by_id('J-password')
    password.send_keys('密码')
    time.sleep(3)
    submit_login=bro.find_element_by_id('J-login')
    submit_login.click()
    time.sleep(3)

    print(bro.get_cookies())
    time.sleep(10)
    bro.get('https://www.12306.cn/index/')
    time.sleep(5)

except Exception as e:
    print(e)
finally:
    bro.close()
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值