爬虫----day03(bs4介绍、遍历与搜索、css选择器、selenium基本使用、无界面浏览器、用selenium 模拟登录百度、selenium其它用法 查找标签、获取标签的属性、标签的点击、输入等、执行js代码、打开空页面等)

昨日回顾

# 1 request 高级用法
	-解析josn:发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-vaule,响应状态码,cookie
            		响应体

    -代理池:搭建免费代理池
    	-开源的---》原理
        	爬取免费代理---》验证---》存到redis中
            起了一个flask服务,监听5000,访问地址,就可以随机获取代理
    -自己的django 测试使用代理
    -超时
    -异常
    -上传文件

# 2 内网穿透
	-花生壳

# 3 爬取视频网站
	-请求头中的数据
    -请求回来的数据,不一一定能直接用

# 4 爬取新闻
	-bs4:find_all,find

.
.
.
.
.
.
.

今日内容

1 bs4介绍,遍历文档树


# 安装:pip install beautifulsoup4
# pip install lxml      # 第三方解析库 要用就下载一下


# 获取的数据如果是json格式,直接解析出来,就能拿到数据
# 获取的数据如果是html或xml格式,用re正则去解析比较麻烦
# 使用beautifulsoup4比使用re解析html或xml格式更方便


# beautifulsoup4  是从HTML或XML文件中提取数据的Python库
# 用它来解析爬取回来的xml格式的数据比较方便

-------------------------------------------------

# bs4 的主要作用就两个:
    查找标签,然后解析出标签的类容

# soup=BeautifulSoup('要解析的内容str类型','要用的解析库html.parser或lxml')

-------------------------------------------------

.
.
.
.
.
.

1.1 bs4的遍历文档树


from bs4 import BeautifulSoup

# 模拟从网站上爬取回来的xml数据,用bs4来拿想要的数据
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title">
    lqz   888
    <h1> 啊啊啊 </h1>
    <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  brother" id="link1" name='lqzsb'>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)   # 跨层  只找第一个

# 和soup.find(name='p')   的区别是:查到的结果没有区别,但是find是搜索找,点的方式是遍历找
# find() 效率可能会高一点

'''
都是这个结果
<p class="title">
    lqz
    888
</p>
'''

------------------------------------
# 3、获取标签的名称  a标签的名字就是a
print(soup.a.name)     # a


# 4、获取标签的属性-----属性字典
print(soup.a.attrs)     # 查找到的a标签里面的所有属性都放到字典里面
print(soup.a.attrs['href'])    # http://example.com/elsie
print(soup.a.attrs.get('class'))    # ['sister', 'brother']
# class对应的属性可能会有多个所以是个列表包裹

print(soup.a.attrs.get('name'))  # lqzsb

-------------------------------------------------
# 5、获取标签的内容

# text  获得该标签内部子子孙孙所有标签的文本内容  放到一起做成字符串
print(soup.p.text)
'''
    lqz   888
    The Dormouse's story
'''

# string  p下只有一个文本时,能取到,否则结果为None  有时候结果不准
print(soup.p.string)  # None



# 5、嵌套选择  就是可以一直点只要有
print(soup.html.body)


---------------- 了解,用的不多  ----------------

# 6、子节点、子孙节点
print(soup.body.contents)   # p下所有子节点,只取一层,子节点里的子节点不取
print(list(soup.p.children))   # 得到一个迭代器用list转一下,包含p下所有子节点  也只取一层

print(list(soup.body.descendants))  # generator  子子孙孙标签都取 这个不好用!!


# 7、父节点、祖先节点
print(soup.a.parent)  # 获取a标签的父节点  直接父亲
print(list(soup.a.parents) )  # 找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲...

# 8、兄弟节点
print(soup.a.next_sibling)  # 下一个兄弟
print(soup.a.previous_sibling)  # 上一个兄弟


print(list(soup.a.next_siblings))   # 下面的兄弟们=>生成器对象
print(list(soup.a.previous_siblings))   # 上面的兄弟们=>生成器对象

------------------------------------------

.
.
.
.
.
.

1.2 bs4搜索文档树


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 查询条件是字符串

# 查询标签名是p的所有标签
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)  # 所以该结果是包裹该文本内容的标签
# 该语法认为文本内容也算一个标签,所以结果是:
# <a class="sister" href="http://example.com/el" id="link1">Elsie</a>

-----------------------------------------------

# 2 查询条件是 正则表达式
import re   # 要先引入正则模块

res = soup.find_all(id=re.compile('^l'))  # id 以1开头的所有标签
res = soup.find_all(class_=re.compile('^s'))  # 类名以s 开头的所有标签
print(res)

-----------------------------------------------

# 3 查询条件是 列表
res = soup.find_all(id=['link1', 'link2'])    # 查找 id 在列表里面的所有标签
print(res)
print(soup.find_all(name=['a', 'b']))    # 查找标签名在列表里面的所有标签

-----------------------------------------------

# 4 查询条件是  True       重要!!!

res = soup.find_all(id=True)  # 查找所有,有id属性的标签
res = soup.find_all(href=True)  # 查找所有,有href属性的标签
res=soup.find_all(class_=True)   # 查找所有,有class属性的标签
print(res)

-----------------------------------------------

# 5 查询条件是 方法  用的不多
def has_class_but_no_id(tag):
    return tag.has_attr('class') and not tag.has_attr('id')

# tag代表的就是当前遍历到的标签

print(soup.find_all(name=has_class_but_no_id))
# 获取有class属性但没有id属性的所有标签

-----------------------------------------------

.
.
.
.

1.3 find的其他参数


name
class_
id
text
attrs
--------------------------------
limit:限制调试,  给find_all用的    find本质是find_all  limit=1

recursive: 查找的时候,等于False只找第一层
默认是True,子子孙孙都找

-r 就是recursive递归的意思

.
.


# limit 参数
res=soup.find_all(href=True,limit=2)
print(res)


# recursive=True  递归查找查找,子子孙孙都找
res=soup.find_all(name='b',recursive=False)  # recursive=False 只找第一层
res=soup.find_all(name='b')

-----------------------------------------------

# 建议遍历和搜索一起用,遍历很快,再搜索慢点     先通过遍历缩小范围,然后再搜索好一点
res=soup.html.body.p.find_all(name='b',recursive=False)
print(res)


.
.
.
.
.
.
.
.
.
.
.

2 bs4也支持css选择器


# 之前学过css选择器,可以很复杂

    .类名     # 类名选择器
    #id        # id选择器
    p          # 标签选择器

# 咱们只学了bs4的lxml解析器 ,以后可能见到别的解析器
# 他们都会支持css选择器,也会支持xpath  这两个东西是通用的  多数解析器都能用


# find搜索与点的遍历都是bs4模块独有的
# 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'))   # 搜索所有 id 叫link1的标签

print(soup.select('#link1 span'))  # 搜索所有 id 叫link1的标签下的后代span标签
print(soup.select('#link1>span'))  # 搜索所有 id 叫link1的标签下的儿子span标签

------------------------------------------
------------------------------------------

# 终极大招------如果不会写css选择器,可以复制
# 直接到浏览器里面  找到对应的标签,右键,点复制,再点复制selector,就拿到该标签的ccs标签选择器了

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可以实现,可见即可爬的效果,因为就是让浏览器操作的
可能页面上的部分内容是ajax请求响应的数据渲染的,用requests朝当前页面网站发请求是拿不到这些数据的


selenium本质是通过驱动浏览器,完全模拟浏览器的操作,
比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器


# 用了selenium操作浏览器,可以直接避开好多的反扒措施!!!


# 通过python使用appnium模块可以操作手机
参见博客 https://blog.csdn.net/Makasa/article/details/121287286
参见博客 https://blog.csdn.net/weixin_42382016/article/details/122468281
------------------------------------------------------

# 使用步骤:
1 下载 pip3.8 install selenium
2 操作浏览器:分不同浏览器,需要下载不同浏览器的驱动
    建议用谷歌---谷歌浏览器驱动:https://registry.npmmirror.com/binary.html?path=chromedriver/
    跟谷歌浏览器版本要对应  113.0.5672.93   查看浏览器---帮助---关于谷歌浏览器里能查到版本
    谷歌对该模块的支持最好,selenium要操作谷歌浏览器,需要用该驱动

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格式!!!)
# 直接就把https://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3 的整个页面的html标签内容都拿回来了!!!
# 用变量接收一下,就可以用bs4去解析想要的数据了!!!


with open('1.html','w',encoding='utf-8') as f:
    f.write(bro.page_source)

time.sleep(5)
bro.close()  # 自动关闭浏览器

-----------------------------------

# 如果直接用requests来拿该页面的数据,拿到的数据是有问题的
import requests
res = requests.get('https://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3')
print(res.text)  # 数据又少,还乱码,百度有反扒

-----------------------------------

找到对应浏览器的版本驱动,下载压缩包,解压后,把exe的驱动文件,放到项目里面去
image
image
.
image
.
.
.
.
.
.
.
.
.
.

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 用selenium 模拟登录百度


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)  # 等待


# By是要指定按什么方式去找标签或者叫定位     LINK_TEXT 表示文本内容的方式
# By.LINK_TEXT 按超链接的文本内容找标签     找文本内容有登录两个字的a标签
btn = bro.find_element(by=By.LINK_TEXT, value='登录')


# 从页面中找到登录 a标签,点击它
btn.click()



# 找到按账号登录的点击按钮,有id,优先用id,因为唯一  TANGRAM__PSP_11__changePwdCodeItem
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('18752386213')    # 往输入框填数据
password.send_keys('tengyifan888')
time.sleep(3)


# 再查找提交的按钮,再点击登录按钮
submit=bro.find_element(by=By.ID,value='TANGRAM__PSP_11__submit')
submit.click()
time.sleep(10)

bro.close()  # 关闭浏览器

# 整个模拟登录百度的动作链就结束了

.
.
.
.
.
.
.
.

5 selenium其它用法

5.0 查找标签


# 有时候用css选择器,查找标签可能会找不到,试试用其他的方法来找

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')  # 浏览器地址栏输入网站访问



# 两个方法
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.send_keys('性感美女')

input_2=bro.find_element(by=By.TAG_NAME,value='img')  # 按标签名找
# 可以按标签名找,一般配合查所有find_elements 来查找所有的对应标签用


input_3=bro.find_element(by=By.CLASS_NAME,value='s_ipt')  # 可以按类名
input_4=bro.find_element(by=By.LINK_TEXT,value='登录')  # 可以按a标签内容找


input_5=bro.find_element(by=By.PARTIAL_LINK_TEXT,value='录')  # 可以按a标签的模糊内容找
input_6 = bro.find_element(by=By.CSS_SELECTOR, value='#su')   # 可以按css选择器找
input_6.click()


.
.
.
.
.
.
.

5.1 获取位置属性大小,文本


# 先找到对应的标签tag ,然后再用该标签点get_attribute('属性名') ,就拿到了该标签里面的属性了

print(tag.get_attribute('src'))  # 用的最多

tag.text  # 获取标签的文本内容

----------------------------------------

# 这几个了解即可    获取标签ID,位置,名称,大小(了解)

print(tag.id)     # selenium的 id


print(tag.location)
# 返回该标签所在页面的位置,x y轴坐标位置 {'x': 782, 'y': 254}  代表的是该标签的左上角的坐标

print(tag.size)    # 标签的尺寸 {'height': 158, 'width': 158}
# 上面这两个方法可能会用到


print(tag.tag_name)    # 标签名字
----------------------------------------

from selenium import webdriver
import time
from selenium.webdriver.common.by import By
import base64

bro = webdriver.Chrome(executable_path='chromedriver.exe')  # 打开一个谷歌浏览器

bro.get('https://kyfw.12306.cn/otn/resources/login.html')  # 浏览器地址栏输入网站访问
# 加入等待:找标签,如果找不到,就等待 x秒,如果还找不到就报错
bro.implicitly_wait(10)  # 等待

btn = bro.find_element(by=By.LINK_TEXT, value='扫码登录')
btn.click()
time.sleep(2)

img = bro.find_element(by=By.ID, value='J-qrImg')  # 找到img标签
res = img.get_attribute('alt')  #
info1 = img.get_attribute('aria-label')  #
res1 = img.get_attribute('src')
# print(res)
# print(info1)
print(res1)

img_info = base64.b64decode(res1.split(',')[-1])
with open('code_img.png', 'wb') as f:
    f.write(img_info)  # 就把二维码下载下来了

time.sleep(1)
bro.close()  # 关闭浏览器

---------------------------------------------------

.
.
.
.
.
.
.
.

5.2 等待元素被加载


# 代码执行很快,有的标签没来的及加载,直接查找就会报错,   所以要设置等待


# 隐示等待:所有标签,只要去找,  找不到就遵循 等10s的规则
	bro.implicitly_wait(10)


# 显示等待:需要给每个标签绑定一个等待,比较麻烦,没必要

.
.
.
.
.

5.3 元素操作 重要!!!


# 都是要先找到该标签 tag = bro.find_element(  )

# 点击
tag.click()


# 输入内容
tag.send_keys()


# 清空内容
tag.clear()


# 浏览器对象 最大化
bro.maximize_window()


# 浏览器对象  截全屏 并以main.png文件名,保存到本地
bro.save_screenshot('main.png')


.
.
.
.
.

5.4 执行js代码


# 括号里面可以直接写js代码的
bro.execute_script('alert("美女")')  # 引号内部的相当于 用script标签包裹了


# 可以干的事
    -获取当前访问的地址  window.location
    -打开新的标签
    -滑动屏幕----bro.execute_script('scrollTo(0,document.documentElement.scrollHeight)')
    -获取cookie,获取定义的全局变量


# 滑动屏幕到当前页面的最底部
bro.execute_script('scrollTo(0,document.documentElement.scrollHeight)')

--------------------------------------
# 执行js代码
# bro.execute_script('alert("美女")')

bro.execute_script("alert(window.location)")   # 能弹出当前页面的网址

# bro.execute_script('scrollTo(0,document.documentElement.scrollHeight)')

time.sleep(2)

bro.close()  # 关闭浏览器

--------------------------------------

.
.
.
.
.
.

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()')  # 执行js代码打开一个空页面

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 异常处理


import time
from selenium import webdriver

browser=webdriver.Chrome(executable_path='chromedriver.exe')

try:
    browser.get('https://www.baidu.com')
    browser.get('https://www.taobao.com')
    browser.get('http://www.sina.com.cn/')

except Exception as e:
    print(e)

finally:
    browser.close()

# 就是把可能会出异常的代码,放到try里面去

.
.
.
.
.
.
.

作业


# 1 http的get请求和post请求有什么区别
# 2 上课讲的代码写一遍

# 期终架构

posted @   tengyifan  阅读(85)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示