目录
bs4介绍,遍历文档树-bs4搜索文档树-css选择器-selenium基本使用-无界面浏览器-selenium其他用法
昨日回顾
# 1 request 高级用法
解析json:发送http请求 返回的数据 可能是xml格式 json格式
request.get().json()
ssl认证
http和https的区别
https=http+ssl/tsl
http版本区别
0.9:底层基于tcp 每次http请求 都是建立一个tcp连接 三次握手 请求结束需要四次挥手
1.1:请求头中有个参数Keep-alive 可以保证多个http请求共用一个tcp连接
2.x:多路复用 多个请求使用同一个数据包
代理:
发送请求 如果使用自己的ip 可能会被封(加黑名单) 需要使用代理ip
如果使用了代理ip 还能不能访问本地的django项目---> 不能
res = requests.post('https://www.cnblogs.com',proxies={'http':'27.79.236.66:4001'})
高匿代理 透明代理
http请求头:x-forword-for user-agent cookie referer contenType
http:
请求协议:
请求首行:请求头地址 请求方式 http的版本
请求头:key-value
请求体
响应协议:
响应首行:响应状态码 响应字符串描述
响应头:key-value 响应状态码 cookie
响应体
代理池:搭建免费代理池
开源的---> 原理
爬取免费代理---> 验证---> 存到redis中
起了一个flask服务 监听5000 访问地址 就可以随机获取代理
自己的django 测试使用代理
超时
异常
上传文件
# 内网穿透
花生壳
# 爬取视频网站
请求头中的数据
请求回来的数据 不一定能直接用
# 爬取新闻
bs4:find_all find
今日内容详细
0 bs4介绍 遍历文档树
# beautifulsoup4 从HTML或XML文件中提取数据的python库
# 用它来解析爬取回来的xml
# 安装:pip install beautifulsoup4
pip install lxml #解析库
# soup=BeautifulSoup('要解析的内容str类型', 'html.parser/lxml')
0.1 bs4的遍历文档树
from bs4 import BeautifulSoup
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title">
lqz
<b>The Dormouse's story</b>
</p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1" name='lqz'>Elsie</a>
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
soup=BeautifulSoup(html_doc,'lxml')
# 1 美化,不是标准xml,完成美化
# print(soup.prettify())
# 2 遍历文档树---》通过 . 来遍历
# print(soup.html.body.p) # 一层一层找
# print(soup.p) # 跨层 只找第一个
# 3 获取标签的名称
# print(soup.a.name)
# 4 获取标签的属性 ---》属性字典
# print(soup.a.attrs['href'])
# print(soup.a.attrs.get('class')) # class 会有多个 ['sister']
# print(soup.a.attrs.get('name'))
# 5 获取标签的内容
# text 获取该标签内部子子孙孙所有标签的文本内容
print(soup.p.text)
# string p下的文本只要一个时 取到 否则为None
print(soup.p.string)
# strings
print(list(soup.p.strings)) # strings为生成器对象
# 6 嵌套选择
print(soup.html.body) # 其实就是点多个 嵌套
# --------------------了解-----------------------
# 7 子节点 子孙节点
print(soup.body.contents) # contents拿p下所有子节点 只取一层
print(list(soup.p.children)) # children得到一个迭代器 包含p下所有子节点 只取一层
print(list(soup.body.descendants)) # descendants 也是得到迭代器 拿到该p标签下的子子孙孙
# 8 父节点、祖先节点
# print(soup.a.parent) #获取a标签的父节点 直接父亲
# print(list(soup.a.parents) )#找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲...
# 9 兄弟节点
# print(soup.a.next_sibling) #下一个兄弟
# print(soup.a.previous_sibling) #上一个兄弟
#
# print(list(soup.a.next_siblings)) #下面的兄弟们=>生成器对象
print(list(soup.a.previous_siblings)) #上面的兄弟们=>生成器对象
1 bs4搜索文档树
# find--->默认找第一个 find_all--->默认找全部
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b>
</p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'lxml')
# 五种过滤器: 字符串、正则表达式、列表、True、方法
# 1 字符串--->查询的条件是字符串
# res=soup.find_all(name='p')
# res=soup.find_all('p')
# print(res)
# 类名叫sister的所有标签
# res=soup.find_all(class_='sister')
# print(res)
# id 叫link1的标签
# res=soup.find_all(id='link1')
# print(res)
# 文本内容叫Elsie的父标签
# res=soup.find(text='Elsie').parent
# print(res)
# 另一种方式---> 写在attrs中 以字典键值对形式
res = soup.find_all(attrs={'class': 'sister'})
res1 = soup.find_all(attrs={'id': 'link1'})
print(res)
print(res1)
# 2 正则表达式
# import re
# # res=soup.find_all(id=re.compile('^l'))
# res=soup.find_all(class_=re.compile('^s'))
# print(res)
# 3 列表
# res=soup.find_all(id=['link1','link2'])
# print(res)
# print(soup.find_all(name=['a','b']))
# print(soup.find_all(['a','b']))
# 4 True
# res=soup.find_all(id=True) # 所有有id的标签
# res=soup.find_all(href=True)
# res=soup.find_all(class_=True)
# print(res)
# 5 方法
def has_class_but_no_id(tag):
return tag.har_attr('class') and not tag.has_attr('id')
print(soup.find_all(name=has_class_but_no_id))
1.1 find的其他参数
name
class_
id
text
attrs
limit:限制测试 find_all用的 find的本质是find_all limit=1
recursive:查找的时候 是只找第一层还是子子孙孙都找 默认是True 子子孙孙都找
# limit参数
res0 = soup.find_all(href=True, limit=2)
print(res0)
print('--------------------------')
# recursive 查找的时候 是只找第一层还是子子孙孙都找
res = soup.find_all(name='b', recursive=False)
res1 = soup.find_all(name='b')
print(res) # 只找第一层 找不到 []
print(res1)
# 建议遍历和搜索一起用
res2 = soup.html.body.p.find_all(name='b', recursive=False)
print(res2)
2 css选择器
# 之前学过css选择器 可以很复杂
.类名
#id
p
# 咱们只学了bs4 以后可能见到别的解析器(lxml)---> 他们都会支持css选择器 也会支持xpath
# bs4 支持css选择器
# html_doc = """
# <html><head><title>The Dormouse's story</title></head>
# <body>
# <p class="title">
# <b>The Dormouse's story</b>
# Once upon a time there were three little sisters; and their names were
# <a href="http://example.com/elsie" class="sister" id="link1">
# <span>Elsie</span>
# </a>
# <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
# <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
# <div class='panel-1'>
# <ul class='list' id='list-1'>
# <li class='element'>Foo</li>
# <li class='element'>Bar</li>
# <li class='element'>Jay</li>
# </ul>
# <ul class='list list-small' id='list-2'>
# <li class='element'><h1 class='yyyy'>Foo</h1></li>
# <li class='element xxx'>Bar</li>
# <li class='element'>Jay</li>
# </ul>
# </div>
# and they lived at the bottom of a well.
# </p>
# <p class="story">...</p>
# """
from bs4 import BeautifulSoup
# soup=BeautifulSoup(html_doc,'lxml')
# select内写css选择器
# print(soup.select('.sister'))
# print(soup.select('#link1'))
# print(soup.select('#link1 span'))
# 终极大招---> 如果不会写css选择器 可以复制
import requests
res=requests.get('https://www.w3school.com.cn/css/css_selector_attribute.asp')
soup=BeautifulSoup(res.text,'lxml')
# print(soup.select('#intro > p:nth-child(1) > strong'))
print(soup.select('#intro > p:nth-child(1) > strong')[0].text)
3 selenium基本使用
# selenium
selenium最初是一个自动化测试工具 而爬虫中使用它主要是为了解决requests无法知己执行JavaScript代码的问题
selenium本质是通过驱动浏览器 完全模拟浏览器的操作 比如跳转 输入 点击 下拉等 来拿到网页渲染之后的结果 可支持多种浏览器
# 使用步骤:
1 下载selenium
2 操作浏览器:分不同的浏览器 需要下载不同浏览器的驱动
用谷歌---> 谷歌浏览器驱动:
https://registry.npmmirror.com/binary.html?path=chromedriver/
跟谷歌浏览器版本要对应 111.0.5563.65:
3 下载完的驱动 放在项目路径下
4 写代码 控制谷歌浏览器
'''
from selenium import webdriver
import time
bro = webdriver.Chrome(executable_path='chromedriver.exe') # 打开一个谷歌浏览器
bro.get('https://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3') # 在地址栏中输入地址
print(bro.page_source) # 当前页面的内容 (html格式)
with open('1.html','w',encoding='utf-8') as f:
f.write(bro.page_source)
time.sleep(5)
bro.close() # 关闭浏览器
'''
# 成功将页面数据下载下来并保存在本地
4 无界面浏览器
from selenium import webdriver
import time
from selenium.webdriver.chrome.options import Options
# 隐藏浏览器的图形化界面,但是数据还拿到
chrome_options = Options()
chrome_options.add_argument('window-size=1920x3000') #指定浏览器分辨率
chrome_options.add_argument('--hide-scrollbars') #隐藏滚动条, 应对一些特殊页面
chrome_options.add_argument('blink-settings=imagesEnabled=false') #不加载图片, 提升速度
chrome_options.add_argument('--headless') #浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败
# chrome_options.binary_location = r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" #手动指定使用的浏览器位置
bro = webdriver.Chrome(executable_path='chromedriver.exe',chrome_options=chrome_options) # 打开一个谷歌浏览器
# 隐藏浏览器的图形化界面,但是数据还拿到
bro.get('https://www.cnblogs.com/') # 在地址栏中输入地址
print(bro.page_source) # 当前页面的内容 (html格式)
time.sleep(5)
bro.close() # 关闭浏览器
4.1 模拟登录百度
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
bro = webdriver.Chrome(executable_path='chromedriver.exe') # 打开一个谷歌浏览器
bro.get('https://www.baidu.com')
# 加入等待:找标签,如果找不到,就等待 x秒,如果还找不到就报错
bro.implicitly_wait(10) # 1 等待
# 从页面中找到登录 a标签,点击它
# By.LINK_TEXT 按a标签文本内容找
btn = bro.find_element(by=By.LINK_TEXT, value='登录')
# 点击它
btn.click()
# 找到按账号登录的点击按钮,有id,优先用id,因为唯一 TANGRAM__PSP_11__changePwdCodeItem
btn_2 = bro.find_element(by=By.ID, value='TANGRAM__PSP_11__changeSmsCodeItem')
btn_2.click()
time.sleep(1)
btn_2 = bro.find_element(by=By.ID, value='TANGRAM__PSP_11__changePwdCodeItem')
btn_2.click()
time.sleep(1)
name = bro.find_element(by=By.ID, value='TANGRAM__PSP_11__userName')
password = bro.find_element(by=By.ID, value='TANGRAM__PSP_11__password')
name.send_keys('[email protected]')
password.send_keys('1234')
time.sleep(1)
submit=bro.find_element(by=By.ID,value='TANGRAM__PSP_11__submit')
submit.click()
time.sleep(2)
bro.close() # 关闭浏览器
'''
自动化打开关闭浏览器
'''
5 selenium其他用法
5.0 查找标签
# 两个方法
bro.find_element 找一个
bro.find_elements 找所有
# 可以按id,标签名,name属性名,类名,a标签的文字,a标签的文字模糊匹配,css选择器,xpath【后面聊】
# input_1=bro.find_element(by=By.ID,value='wd') # 按id找
# input_1 = bro.find_element(by=By.NAME, value='wd') # name属性名
# input_1=bro.find_element(by=By.TAG_NAME,value='input') # 可以按标签名字找
# input_1=bro.find_element(by=By.CLASS_NAME,value='s_ipt') # 可以按类名
# input_1=bro.find_element(by=By.LINK_TEXT,value='登录') # 可以按a标签内容找
# input_1=bro.find_element(by=By.PARTIAL_LINK_TEXT,value='录') # 可以按a标签内容找
# input_1 = bro.find_element(by=By.CSS_SELECTOR, value='#su') # 可以按css选择器
5.1 获取位置属性大小 文本
print(tag.get_attribute('src')) # 用的最多
tag.text # 文本内容
# 获取标签ID 位置 名称 大小(了解)
print(tag.id)
print(tag.location)
print(tag.tag_name)
print(tag_size)
5.2 等待元素被加载
# 代码执行的很快 有的标签没来得及加载 直接查找就会报错 设置等待
# 隐士等待:所有标签 只要去找 找不到就遵循 等10s的规则
bro.implicitly_wait(10)
# 显示等待:需要给每个标签绑定一个等待 麻烦
5.3 元素操作
# 点击
tag.click()
# 输入内容
tag.send_keys()
# 清空内容
tag.clear()
# 浏览器对象 最大化
bro.maximize_window()
# 浏览器对象 截全屏
bro.save_srceenshot('amin.png')
5.4 执行js代码
bro.execute_script('alert("美女")') # 引号内部的相当于 用script标签包裹了
# 可以干的事
获取当前访问的地址 window.location
打开新的标签
滑动屏幕--->
bro.execute_script('scrollTo(0,document.documentElement.scrollHeight)')
获取cookie 获取定义的全局变量
5.5 切换选项卡
import time
from selenium import webdriver
browser=webdriver.Chrome(executable_path='chromedriver.exe')
browser.get('https://www.baidu.com')
browser.execute_script('window.open()')
print(browser.window_handles) #获取所有的选项卡
browser.switch_to.window(browser.window_handles[1])
browser.get('https://www.taobao.com')
time.sleep(2)
browser.switch_to.window(browser.window_handles[0])
browser.get('https://www.sina.com.cn')
browser.close()
'''
执行流程:
打开一个新的选项卡(页面)---> 在新的选项卡中打开淘宝---> 返回第一个页面打开新浪
'''
5.6 浏览器前进后退
import time
from selenium import webdriver
browser=webdriver.Chrome(executable_path='chromedriver.exe')
browser.get('https://www.baidu.com')
browser.get('https://www.taobao.com')
browser.get('http://www.sina.com.cn/')
browser.back()
time.sleep(2)
browser.forward()
browser.close()
5.7 异常处理
# 将打开页面 控制页面的操作用try包裹起来 出错抛异常
'''以后写就按这个模板'''
import time
from selenium import webdriver
browser=webdriver.Chrome(executable_path='chromedriver.exe')
try:
except Exception as e:
print(e)
finally:
browser.close()
补充
# http的get请求和post请求有什么区别
1 get和post是HTTP请求的两种方式 底层都是基于TCP\IP协议进行通信的。get和post本质并无区别 只是被HTTP规定了不同的行为和方式。
2 get请求在浏览器后退时无害 不发送请求 post在浏览器后退时会再次发送请求。get参数通常放在url后面传递 post则通常放在请求体中传递。但实际上 get也可以用请求体少量传值 post也可以在url中少量传值 这在技术上是完全行得通的 只是不符合http的规定。
3 get比post更不安全 因为参数之间暴露在url上 所以不能用来传递敏感信息。get在url中传输参数有长度限制 post没有限制。get之所以会限制请求长度 是因为url请求数据量太大对浏览器和服务器都是很大的负担 处理起来有成本 所以浏览器和服务器对单次访问做了限制。大多数浏览器通常都会限制url长度在2K和字节 而大多数服务器最多处理64K大小的url。超过的部分不出来。虽然get可以带请求体 但不能保证一定能被接收到。所以此处的不同 是因为HTTP的规定和浏览器/服务器的限制 导致它们在应用过程中体现出一些不同。所以如果请求参数可能很长很多的话 直接用post即可 如果用get 超过限制 参数传不过去 会报null。
4 get产生一个TCP数据包 post产生两个TCP数据包。对于get方式的请求 浏览器会把HTTP头部和数据一并发送出去 服务器响应200返回数据;而对于post 浏览器会先发送头部 服务器响应100 continue 浏览器再发送数据 服务器响应200返回数据。也就是post请求 第一次将头部发送出去 确认服务器和网络没问题可以服务 才会将真正的数据提交。因为post需要两步 时间上消耗的多一点 所有看起来get比post更快 但并不是所有浏览器都会在post中发送两次包 火狐浏览器的post请求就仅发送一次。
5 get和post都有自己的语义 不能随便混用。get从指定的资源获取数据 post是向指定的资源提交数据。在网络环境好的情况下 发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下 两次包的TCP在验证数据包完整性上 有非常大的优点。也就是说 网络好的话get和post请求效率基本一样 网络不好的时候post对验证请求数据完整性更有优势。
标签:浏览器,get,bs4,selenium,bro,soup,文档,print,find
From: https://www.cnblogs.com/zpf1107/p/17228260.html