?博主介绍
💂 个人主页:苏州程序大白
💂 个人社区:CSDN全国各地程序猿
🤟作者介绍:中国DBA联盟(ACDU)成员,CSDN全国各地程序猿(媛)聚集地管理员。目前从事工业自动化软件开发工作。擅长C#、Java、机器视觉、底层算法等语言。2019年成立柒月软件工作室,2021年注册苏州凯捷智能科技有限公司
💅 有任何问题欢迎私信,看到会及时回复
👤 微信号:stbsl6,微信公众号:苏州程序大白
💬如果文章对你有帮助,欢迎关注、点赞、收藏(一键三连)
🎯 想加入技术交流群的可以加我好友,群里会分享学习资料
爬虫简单入门
爬虫合法性-君子协议
- 关于爬虫的合法性,有君子协议
在网站网址后加上/robots.txt 查看君子协议
准备注意事项
- 做爬虫前尽量不要使用任何网络代理,否则容易出现莫名的问题
手刃一个小爬虫(request 模块实现)
from urllib.request import urlopen
url="http://www.baidu.com"
resp = urlopen(url)
"""
先print(resp.read())查看返回的内容
从中找到编码格式,一般为charset后位置
再进行解码
print(resp.read().decode("utf-8")) #resp.read()从响应中读取内容,并用decode解码
"""
with open("D:\desktop\代码\python测试\Mywebsite.html",mode="w",encoding="utf-8") as web:
web.write(resp.read().decode("utf-8"))
Web 请求、HTTP 协议、抓包
Web 请求过程解析
- 1.服务器渲染:在服务器直接把数据和 html 整合在一起,统一返回给浏览器。
举例:输入**www.baidu.com**,浏览器向百度服务器发送请求,百度返回 html 页面源代码;在百度里搜索关键词,百度在服务器将关键词有关数据写入 html 页面源代码中,一并返回给浏览器 - 2.客户端渲染:第一次请求只要一个 html 骨架,第二次请求拿到数据,进行数据展示。在页面源代码中,看不到数据。
举例:例如豆瓣电影排行榜的分类筛选网页,浏览器先向服务器请求,服务器返回 html 骨架(不包含数据),浏览器第二次请求,服务器返回数据,浏览器将 html 骨架与数据渲染结合,呈现页面。在源代码处搜索呈现的数据,无法找到。 - 熟练使用浏览器抓包工具:
Chrome 浏览器右键检查或者 F12,上方大类选择 Network; 刷新页面,此时所有返回的请求都在此处显示。点击文件可以打开源代码,通常第一个文件为网页骨架; Headers 中 Request URL 写有 url 地址,Preview 可以查看预览效果。在这些文件中通过预览找到和页面内容匹配的数据,回到 Headers 即可找到数据 url - 想要得到数据,无需骨架,对于爬虫而言,目的为得到数据,骨架无影响
HTTP 协议
-
HTTP 协议基本概念
-
抓包工具及获得的重要信息:
附:请求方式:
- Get:显示提交(常用于搜索,通常只读)
- Post:隐式提交(常用于对数据增删改,通常可写入)
requests 模块入门
模块安装
requests 模块为第三方支持库,需要手动安装
pip install requests
Requests 入门-1
GET 请求:将搜狗搜索内容爬取,并学习简单的反爬
import requests
url = "https://www.sogou.com/web?query=周杰伦"
dict = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36"}
resp = requests.get(url,headers=dict)
print(resp.text)
resp.close()
可以进行一些小修改,做到更改搜索对象:
import requests
query=input("输入你要搜索的内容:")
url = f"https://www.sogou.com/web?query={query}"
dict = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36"}
resp = requests.get(url,headers=dict)
print(resp.text)
resp.close()
Requests 入门-2
POST 请求:爬取百度翻译的结果
"""
打开百度翻译后按F12进入抓包工具,清除多余的文件,注意输入法切换为英文,输入英文单词后,翻译框下方有一个小列表
在抓包工具中通过preview预览尝试寻找列表的数据文件,发现sug文件为数据文件
打开sug文件的Headers,获取需要的信息:url地址,请求方式为POST
打开Payload,找对From Data,为POST传参数据,对于上个GET程序中利用f-string传入参数的方式就不灵了
"""
import requests
url = "https://fanyi.baidu.com/sug"
word = input("请输入你要翻译的英文:")
dat = {"kw":word}
resp = requests.post(url,data=dat)
print(resp.json())
resp.close()
Requests 入门-3
浏览器渲染的二次 GET 请求网页: 豆瓣电影分类排行榜-喜剧
- 通常网站 url 里有问号”?”,问号前的是 url,问号后的是参数
"""
豆瓣电影分类排行榜网页通过浏览器渲染,有两次数据传递
在抓包工具中选择筛选XHR类别(常表示二次请求数据),找到跟页面差不多的蕴含量大一些的XHR文件,就是页面的数据文件找到数据文件Headers:
查看url,通常网站url里有问号"?",问号前的是url,问号后的是参数,查看请求方式为GET方式
在Payload中有Query String Parameters(url问号后参数),
"""
import requests
url = "https://movie.douban.com/j/chart/top_list"
param = {
"type": "24",
"interval_id": "100:90",
"action":"" ,
"start": "0",
"limit": "20"
}
header = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36"}
resp = requests.get(url,params=param,headers=header)
print(resp.json())
resp.close()
- 在豆瓣中下拉,刷新出新的电影,同时 Query String Parameters 中出现新的数据,与原数据对比发现只有 Query String Parameters 的 start 参数变化,可以借此修改代码中 start 参数实现新效果
数据解析
数据解析概述
Re 解析_正则表达式
- Re 解析:Regular Expression 的简写,正则表达式,一种使用表达式的方式对字符串进行匹配的语法规则
- 我们抓取到的网页源代码本质上就是一个超长的字符串。,想从里面提取内容,用正则表达式再合适不过了
- 优点:速度快,效率高,准确性高
缺点:新手上手难度较大 - 不过只要掌握了正则编写的的逻辑关系,写出一个提取页面内容的正则并不复杂
- 正则的语法:使用元字符进行排列组合用来匹配字符串
在线测试正则表达式https://tool.oschina.net/regex/ - 元字符:具有固定含义的特殊符号
- 常用元字符
- 量词:控制前面的元字符出现的次数
- 贪婪匹配和惰性匹配
这两个着重说一下,写爬虫用的最多的就是惰性匹配 *? 表示尽可能少的让* 匹配东西
Bs4 解析_HTML 语法
- Bs4 解析:Beautiful Soup4 的简写,简单易用的 HTML 解析器,需要掌握一些 HTML 语法
- HTML(Hyper Text Markup Language)超文本标记语言,是编写网页最基本、最核心的语言,其语法就是用不同的标签,对网页上的内容进行标记,从而使网页显示不同的效果,简单举例:
<h1>I Love You</h1>
- 常用标签:
- 属性:标签内后跟的控制标签行为的属性,其后所写的为属性值,简单举例:
<h1 align="right">I Love You</h1>
借此实现标题文字右对齐,其中,align 为属性,right 为属性值
<标签 属性="值" 属性="值">被标记的内容</标签>
Xpath 解析_XML 概念
- Xpath 解析:XML 解析器,用来提取XML 文档中的节点,Xpath 是在 XML 文档中搜索的一门语言。HTML 是 XML 的一个子集
- 基础概念:
<book>
<id>1</id>
<name>野花遍地香</name>
<price>1.23<price>
<author>'
<nick>周大强</nick>
<nick>周芷若</nick>
</author>
</book>
在上述 html 中:
book ,id ,name ,price 等都被称为节点id ,name ,price ,author 被称为book 的子节点,book 被称为他们的父节点id ,name ,price ,author 被称为同胞节点
python 实现 Re 解析
Python 的 re 模块使用
在 python 中使用正则表达式,可以使用re 模块,re 模块记住几个常用功能就足够我们日常使用了:
import re
list = re.findall("\d+","我的电话号是10086,我朋友的电话是10010")
print(list,"\n")
it = re.finditer("\d+","我的电话号是10086,我朋友的电话是10010")
for i in it:
print(i.group())
print()
s = re.search("\d+","我的电话号是10086,我朋友的电话是10010")
print(s.group(),"\n")
a = re.match("\d+","10086,我朋友的电话是10010")
print(a.group(),"\n")
obj = re.compile("\d+")
ret = obj.finditer("我的电话号是10086,我朋友的电话是10010")
for it in ret:
print(it.group())
print()
s="""
<div class='jay'><span id='1'>雷军</span></div>
<div class='jj'><span id='2'>李彦宏</span></div>
<div class='jolin'><span id='3'>张小龙</span></div>
<div class='sylar'><span id='4'>马云</span></div>
<div class='tory'><span id='5'>马化腾</span></div>
"""
obj1 = re.compile("<div class='.*?'><span id='\d+'>.*?</span></div>",re.S)
result = obj1.finditer(s)
for it in result:
print(it.group())
print()
obj1 = re.compile("<div class='.*?'><span id='\d+'>(?P<gualudeng>.*?)</span></div>",re.S)
result = obj1.finditer(s)
for it in result:
print(it.group("gualudeng"))
print()
手刃豆瓣 top250
豆瓣 top250
from email import header
import requests,re,csv
url = "https://movie.douban.com/top250"
ua = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36"}
resp = requests.get(url,headers=ua)
page_content = resp.text
obj = re.compile('<li>.*?<div class="item">.*?<span class="title">(?P<title>.*?)</span>.*?<p class="">.*?<br>(?P<year>.*?) .*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>',re.S)
result = obj.finditer(page_content)
for it in result:
print("\n电影名:",it.group("title"),"\n年份:",it.group("year").strip(),"\n评分:",it.group("score"))
f = open("data.csv",mode="w",encoding="utf-8")
csvwriter = csv.writer(f)
result = obj.finditer(page_content)
for it in result:
dic= it.groupdict()
dic["year"] = dic["year"].strip()
csvwriter.writerow(dic.values())
f.close()
print("over!")
参考源代码:
屠戮盗版天堂电影信息
盗版天堂 补充 html 中 a 标签超链接知识
"""
1、确认数据在页面源码中,定位到2022必看热片
2、从2022必看热片中提取到子页面链接地址
3、请求子页面的链接地址,拿到想要的下载地址
"""
import requests,re
main_url = "https://dytt89.com/"
child_url_list = []
resp = requests.get(main_url , verify=False)
resp.encoding = "gb2312"
obj1 = re.compile('2022必看热片.*?<ul>(?P<ul>.*?)</ul>',re.S)
obj2 = re.compile("<a href='(?P<href>.*?)'",re.S)
result1 = obj1.finditer(resp.text)
for it in result1:
ul = it.group("ul")
result2 = obj2.finditer(ul)
for itt in result2:
add = itt.group("href")
child_url = main_url + add.strip("/")
child_url_list.append(child_url)
obj3 = re.compile('◎片 名(?P<movie>.*?)<br />.*?<td style="WORD-WRAP: break-word" bgcolor="#fdfddf"><a href="(?P<download>.*?)">',re.S)
for url in child_url_list:
child_resp = requests.get(url)
child_resp.encoding = "gb2312"
result3 = obj3.search(child_resp.text)
print(result3.group("movie"))
print(result3.group("download"))
参考源代码:
python 实现 Bs4 解析
Python 的 bs4 模块使用
python 的 bs4 模块为第三方模块,需要先安装,安装 cmd 语法如下:
pip install bs4
抓取示例:北京新发地菜价(已失效,仅可参考)
北京新发地地址(已重构) 注:页面重构,下示例代码仅可参考,无法运行,网站改为浏览器渲染,使用 POST 请求
import requests
import csv
from bs4 import BeautifulSoup
url = "http://www.xinfadi.com.cn/marketanalysis/0/list/1.shtml"
resp = requests.get(url)
f = open("菜价.csv", mode="w")
csvwriter = csv.writer(f)
page = BeautifulSoup(resp.text, "html.parser")
table = page.find("table", class_="hq_table")
trs = table.find_all("tr")[1:]
for tr in trs:
tds = tr.find_all("td")
name = tds[0].text
low = tds[1].text
avg = tds[2].text
high = tds[3].text
kind = tds[4].text
set = tds[5].text
date = tds[6].text
csvwriter.writerow([name, low, avg, high, kind, set, date])
f.close()
print("over")
参考源代码:
抓取优美图库的图片**(已失效,仅可参考)
优美图库(已失效)
import requests
import time
from bs4 import BeautifulSoup
url = "https://umei.cc/bizhitupian/weimeibizhi"
resp = requests.get(url)
resp.encoding = "utf-8"
main_page = BeautifulSoup(resp.text, "html.parser")
alist = main_page.find("div", class_="TypeList").find_all("a")
for a in alist:
href = a.get("href")
child_resp = requests.get(href)
child_resp.encoding = "utf-8"
child_page_text = child_resp.text
child_page = BeautifulSoup(child_page_text, "html.parser")
p = child_page.find("p", align="center")
img = p.find("img")
src = img.get("src")
img_resp = requests.get(src)
img_name = src.split("/")[-1]
with open(img_name, mode="wb") as f:
f.write(img_resp.content)
print("part success!", img_name)
time.sleep(1)
print("all over!")
参考源代码:
python 实现 Xpath 解析
Python 的 lxml 模块使用
python 的 lxml 模块为第三方模块,需要先安装,安装 cmd 语法如下:
pip install lxml
python 中 xpath 解析的使用
from lxml import etree
xml = """......"""
tree = etree.XML(xml)
result1 = tree.xpath("/book/name/text()")
print(result1)
result2 = tree.xpath("/book/author//nick/text()")
result3 = tree.xpath("/book/author/*/nick/text()")
-
补充
etree 可以打开存有 html 代码的文件:tree = etree.parse(存有html的文件) etree.xxx 需要跟相对应的类型,如源码为 html 则为etree.HTML() - 可以在需要的路径后跟
[n] ,表示索引,提取第 n 个节点(注:从 1 开始),如:/book[1]/name/text() - 可以在需要的路径后跟
[@属性="值"] ,表示提取属性值为”值”的节点,如:/book[@id="1"]/name/text() 。不加属性值,表示定位到属性 - 使用相对节点查找时,可以使用
./ ,代替表示当前节点 - 小技巧:当层级较多时,可以使用浏览器抓包工具,网页
检查 ,找到对应代码,右键,copy->Xpath,就可以直接获取路径 -
爬取猪八戒网信息 青岛猪八戒网-搜索写入 saas import requests
from lxml import etree
url = "https://qingdao.zbj.com/search/f/?kw=saas"
resp = requests.get(url)
html = etree.HTML(resp.text)
divs = html.xpath("/html/body/div[6]/div/div/div[2]/div[5]/div[1]/div")
for div in divs:
price = div.xpath("./div/div/a[1]/div[2]/div[1]/span[1]/text()")[0].strip("¥")
title = "saas".join(div.xpath("./div/div/a[1]/div[2]/div[2]/p/text()"))
com_name = div.xpath("./div/div/a[2]/div[1]/p/text()")[0]
place = div.xpath("./div/div/a[2]/div[1]/div/span/text()")[0]
print(price, title, com_name, place)
requests 模块进阶
requests 进阶概述
处理 cookie 模拟浏览器登录
-
浏览器登录网页时,将用户名与密码上传到服务器,服务器内部进行校验,成功后将登录信息返回写入 cookie,下次进行请求时,可以连带 cookie 一起发送给服务器 -
示例:爬取 17k 小说网的用户书架内容 17k 小说网
import requests
session = requests.session()
url = "https://passport/17k.com/ck/user/login"
dat = {
"loginName": "18614075987",
"password": "q6039545"
}
session.post(url, data=dat)
resp = session.get(
"https://user.17k.com/ck/author/shelf?page=1&appKey=2406394919")
print(resp.text)
resp_ = requests.get("https://user.17k.com/ck/author/shelf?page=1&appKey=2406394919", headers={
"cookie": "所需要的cookie,数据文件处抓包获得"
})
print(resp_.text)
防盗链的处理
-
示例:爬取梨视频的视频 梨视频中的一段视频
- 梨视频的视频在抓包工具中视频存放在
video 标签下,而源代码中看不到 video 标签,大致可以推断,视频 video 标签是后期通过 JS 脚本生成出来的 - 所以对于视频,首先抓包检查工具大致确定视频地址,再在源代码中确认一次
- 梨视频,抓包工具,刷新页面,
XHR 中能找到有关视频链接的数据文件,从中获取到抓取到的视频地址 - 抓到的视频不能直接播放,将其与原视频 url 对比,发现其中有一段不同。不同的部分,不能打开的链接将原先的
cont-xxxx 替换为了抓包得到数据中的系统时间,在视频的主页面,链接最后的一串数字就是cont- 后需要的数字
import requests
url = "https://pearvideo.com/video_1759202"
contId = url.split("_")[1]
videoStatus = f"https://pearvideo.com/videoStatus.jsp?contId={contId}&mrd=0.20093235215815763"
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36",
"Referer": "https://pearvideo.com/video_1759202"
}
resp = requests.get(videoStatus, headers=header)
dic = resp.json()
srcURL = dic["videoInfo"]["videos"]["srcUrl"]
systemTime = dic["systemTime"]
srcURL = srcURL.replace(systemTime, f"cont-{contId}")
with open("a.mp4", mode="wb") as f:
f.write(requests.get(srcURL).content)
代理
-
原理:通过第三方的机器去发送请求(需要自己提前寻找代理 IP) 站大爷 IP 66 免费代理 import requests
url = "https://www.baidu.com"
proxies = {
"https": "https://60.217.136.129:8060"
}
resp = requests.get(url, proxies=proxies)
resp.encoding = "utf-8"
print(resp.text)
抓包工具的补充使用
- 浏览器抓包工具中
Initiator 中request call back 项记录了网站调用的 JS 栈,从下往上按时间顺序排列。点击可以进入 JS 源码,点击窗口左下方的大括号可以对源码进行缩进排版,找到需要的发送行设置断点,利用断点调试找到需要的信息,可以借此得到一些网站的加密过程或其他源码(涉及逆向 JS,较为复杂)
线程与进程
基础概念
- 进程:操作系统运行程序时,会为其开辟一块内存空间,专门用于存放与此程序相关的数据,这块内存区域称为xxx 进程
- 线程:在xxx 进程中存在多个线程,共同完成工作
- 进程是资源单位,线程是执行单位。每一个进程至少要有一个线程,且程序执行时会有一个主线程,即可认为启动一个程序默认会有一个主线程
多线程
def func():
for i in range(1000):
print("func", i)
if __name__ == "__main__":
func()
for j in range(1000):
print("main", j)
一个简单的线性单线程程序,主函数中,func 函数执行完毕后才会执行主函数的for 循环
from threading import Thread
def func():
for i in range(1000):
print("func", i)
if __name__ == "__main__":
t = Thread(target=func)
t.start()
for j in range(1000):
print("main", j)
- 多线程示例 2,利用面向对象的特性,自己写一个继承
Thread 的class 类:
from threading import Thread
class MyThread(Thread):
def run(self):
for i in range(1000):
print("子线程", i)
if __name__ == "__main__":
t = MyThread()
t.start()
for j in range(1000):
print("主线程", j)
from threading import Thread
def func(name):
for i in range(1000):
print(name, i)
if __name__ == "__main__":
t1 = Thread(target=func, args=("周杰伦",))
t1.start()
t2 = Thread(target=func, args=("王力宏",))
t2.start()
多进程
- 相对于多线程而言,多进程会开辟新的空间,增加占用,所以平常使用机会不大,多半可以由多线程代替
- 多进程示例(基本与多线程类似):
from multiprocessing import Process
def func():
for i in range(1000):
print("子进程", i)
if __name__ == "__main__":
p = Process(target=func)
p.start()
for j in range(1000):
print("主进程", j)
线程池与进程池
- 线程池:一次性开辟一些线程,用户直接给线程池提交任务,可以节省开辟线程的资源,线程任务的调度交给线程池来完成
- 进程池:同上线程池类似
- 线程池示例
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
def fn(name):
for i in range(1000):
print(name, i)
if __name__ == "__main__":
with ThreadPoolExecutor(50) as t:
for i in range(100):
t.submit(fn, name=f"线程{i}")
print("over")
协程与异步
协程概念
import time
def func():
print("123")
time.sleep(3)
print("456")
if __name__ == "__main__":
func()
- 协程:当程序遇见
IO操作 的时候,可以选择性的切换到其他任务上 在微观上是一个任务一个任务的进行切换,在宏观上我们能看见的是多个任务一起共同执行 这种操作称为多任务异步操作 上方所讲的一切,都是在单线程的条件下
多任务异步协程
import asyncio
async def func():
print("你好,我叫塞丽娜")
if __name__ == "__main__":
g = func()
asyncio.run(func)
import asyncio
import time
async def func1():
print("你好,我叫潘金莲")
await asyncio.sleep(3)
print("你好,我叫潘金莲")
async def func2():
print("你好,我叫王建国")
await asyncio.sleep(2)
print("你好,我叫王建国")
async def func3():
print("你好,我叫李雪琴")
await asyncio.sleep(4)
print("你好,我叫李雪琴")
if __name__ == '__main__':
f1 = func1()
f2 = func2()
f3 = func3()
tasks_ = [
f1, f2, f3
]
t1 = time.time()
asyncio.run(asyncio.wait(tasks_))
t2 = time.time()
print(t2-t1)
import asyncio
async def func1():
print("你好,我叫潘金莲")
await asyncio.sleep(3)
print("你好,我叫潘金莲")
async def func2():
print("你好,我叫王建国")
await asyncio.sleep(2)
print("你好,我叫王建国")
async def func3():
print("你好,我叫李雪琴")
await asyncio.sleep(4)
print("你好,我叫李雪琴")
async def main():
tasks_=[
func1(),func2(),func3()
]
await asyncio.wait(tasks_)
if __name__ == '__main__':
asyncio.run(main())
- 注意:Python3.8后会报警告,由于版本迭代,Python3.11后将不再支持
await asyncio.wait() 中直接传入协程对象,而是需要将协程对象通过asyncio.create_task() 转换为asyncio.Task对象,才能使用,如下:
import asyncio
async def func1():
print("你好,我叫潘金莲")
await asyncio.sleep(3)
print("你好,我叫潘金莲")
async def func2():
print("你好,我叫王建国")
await asyncio.sleep(2)
print("你好,我叫王建国")
async def func3():
print("你好,我叫李雪琴")
await asyncio.sleep(4)
print("你好,我叫李雪琴")
async def main():
tasks_=[
asyncio.create_task(func1()),
asyncio.create_task(func2()),
asyncio.create_task(func3())
]
await asyncio.wait(tasks_)
if __name__ == '__main__':
asyncio.run(main())
异步 http 请求
概述
- 发送请求时,原先的`requests.get()`是一个同步操作,会将异步程序转为同步,需要换成**异步请求操作**
Python 的 aiohttp 模块使用
python 的 aiohttp 模块为第三方模块,需要先安装,安装 cmd 语法如下:
pip install aiohttp
基本语法-下载网站图片
import asyncio
import aiohttp
urls = [
"photo_url1",
"photo_url2",
"photo_url3"
]
async def aiodownload(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
with open("文件名(可以按url地址切割存入变量)", mode="wb") as f:
f.write(await resp.content.read())
async def main():
tasks_ = []
for url in urls:
tasks_.append(aiodownload(url))
await asyncio.wait(tasks_)
if __name__ == '__main__':
asyncio.run(main())
示例:百度小说《西游记》
百度小说《西游记》,注意抓包时展开全部章节
import requests
import asyncio
import aiohttp
import aiofiles
import json
async def aiodownload(cid, book_id, title):
data = {
"book_id": f"{book_id}",
"cid": f"{book_id}|{cid}",
"need_bookinfo": 1
}
data = json.dumps(data)
url = f"https://dushu.baidu.com/api/pc/getChapterContent?data={data}"
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
dic = await resp.json()
async with aiofiles.open(f"D:\Desktop\代码程序\python测试\新建文件夹\{title}.txt", mode="w", encoding="utf-8") as f:
await f.write(dic["data"]["novel"]["content"])
async def getCatalog(url):
resp = requests.get(url)
dic = resp.json()
tasks_ = []
for item in dic["data"]["novel"]["items"]:
title = item["title"]
cid = item["cid"]
tasks_.append(aiodownload(cid, book_id, title))
await asyncio.wait(tasks_)
if __name__ == '__main__':
book_id = "4306063500"
url = 'https://dushu.baidu.com/api/pc/getCatalog?data={"book_id":"' + book_id + '"}'
asyncio.run(getCatalog(url))
selenium 模块
selenium 引入概念
-
某些网页的数据内容被加密了,而浏览器显示的为正常数据,让程序连接到浏览器,让浏览器来完成各种复杂的操作,我们只接收最终的结果 -
selenium 模块:自动化测试工具。它可以打开浏览器,然后像人一样去操作浏览器。程序员可以从selenium 中直接提取网页上的各种信息 -
selenium
的 配置安装 :
安装 selenium 模块:pip install selenium 下载浏览器驱动:selenium 驱动下载地址,下载对应浏览器的对应版本驱动 驱动的存放:将解压后的浏览器驱动放在Python 解释器所在的文件夹下,windows 下即为python 安装目录文件夹中
-
测试(注意模块 Chrome 或其他浏览器要首字母大写):
from selenium.webdriver import Chrome
web = Chrome()
web.get("http://www.baidu.com")
print(web.title)
selenium 基础操作
from selenium.webdriver import Chrome
from selenium.webdriver.common.keys import Keys
import time
web = Chrome()
web.get("http://lagou.com")
el = web.find_element_by_xpath('//*[@id="changeCityBox"]/p[1]/a')
el.click()
time.sleep(1)
web.find_element_by_xpath('//*[@id="search_input"]').send_keys("python", Keys.ENTER)
time.sleep(1)
li_list = web.find_elements_by_xpath('//*[@id="s_position_list"]/ul/li')
for li in li_list:
job_name = li.find_element_by_tag_name("h3").text
job_price = li.find_element_by_xpath("./div/div/div[2]/div/span").text
company_name = li.find_element_by_xpath("./div/div[2]/div/a").text
print(job_name, company_name, job_price)
窗口之间的切换
from selenium.webdriver import Chrome
from selenium.webdriver.common.keys import Keys
import time
web = Chrome()
web.get("http://lagou.com")
web.find_element_by_xpath('//*[@id="changeCityBox"]/p[1]/a').click()
time.sleep(0.5)
web.find_element_by_xpath('//*[@id="search_input"]').send_keys("python", Keys.ENTER)
time.sleep(0.5)
web.find_element_by_xpath('//*[@id="jobList"]/div[1]/div[1]/div[1]/div[1]/div[1]/a').click()
web.switch_to.window(web.window_handles[-1])
job_detail = web.find_element_by_xpath('//*[@id="job_detail"]/dd[2]/div').text
print(job_detail)
web.close()
web.switch_to.window(web.window_handles[0])
from selenium.webdriver import Chrome
web = Chrome()
web.get("https://www.91kanju.com/vod-play/541-2-1.html")
iframe = web.find_element_by_xpath('//*[@id="player_iframe"]')
web.switch_to.frame(iframe)
tx = web.find_element_by_xpath('//*[@id="main"]/h3[1]').text
print(tx)
无头浏览器、下拉菜单 select 的处理、拿到 elements 页面源码
from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.select import Select
import time
opt = Options()
opt.add_argument("--headless")
opt.add_argument("--disable-gpu")
web = Chrome(options=opt)
web.get("https://endata.com.cn/BoxOffice/BO/Year/index.html")
sel_el = web.find_element_by_xpath('//*[@id="OptionDate"]')
sel = Select(sel_el)
for i in range(len(sel.options)):
sel.select_by_index(i)
time.sleep(2)
print(web.page_source)
处理验证码
‘//*[@id=“player_iframe”]’)
切入窗口视角到iframe
web.switch_to.frame(iframe)
切出窗口视角到默认窗口视角
web.switch_to.default_content()
tx = web.find_element_by_xpath(‘//*[@id=“main”]/h3[1]’).text print(tx)
##### **无头浏览器、下拉菜单 select 的处理、拿到 elements 页面源码**
- **无头浏览器**:对于爬虫而言,浏览器的显示界面可以隐藏
- **示例:艺恩电影排行**
[艺恩电影排行(网址已失效)](https://endata.com.cn/BoxOffice/BO/Year/index.html)
```python
from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.select import Select
import time
# 无头浏览器
# 准备好配置参数
opt = Options()
# 添加参数
opt.add_argument("--headless") # 无头
opt.add_argument("--disable-gpu") # 禁用gpu
# =================================================================
# 在Chrome()中参加无头参数
web = Chrome(options=opt)
web.get("https://endata.com.cn/BoxOffice/BO/Year/index.html")
# 网址中有select下拉列表元素,如何处理
# 定位到下拉列表
sel_el = web.find_element_by_xpath('//*[@id="OptionDate"]')
# 对元素进行包装,包装成下拉菜单,需要引入第二行的包
sel = Select(sel_el)
# 让浏览器进行调整选项
# sel.options下拉框的列表的长度作为for循环次数,i就是每一个下拉框选项的索引位置
for i in range(len(sel.options)):
# select_by-xxx处,by_index为按照索引进行切换,by_value为按照select选项value进行切换,by_visible_text为按照所见文本进行切换
sel.select_by_index(i) # 按照索引i进行切换
time.sleep(2) # 等待切换
# 提取数据,此处省略
# =================================================================
# 如何拿到页面源代码Elements数据(经过数据加载以及JS执行之后的结果的html内容)
print(web.page_source)
💫点击直接资料领取💫
??关注苏州程序大白公众号??
👇 👇👇
|