/robots.txt
查看君子协议request
模块实现)#百度
#需求:用程序模拟浏览器,输入一个网址,从该网址中获取到资源或者内容
from urllib.request import urlopen #从包中导入模块
url="http://www.baidu.com" #准备网址
resp = urlopen(url) #用urlopen模拟浏览器打开网址,将返回的响应存入resp
"""
先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: #打开名为"Mywebsite.html"的文件,模式为w写入,as语句将其简称为web,设置encoding打开编码
web.write(resp.read().decode("utf-8")) #resp.read()从响应中读取内容,并用decode解码,将其写入到上述文件
TCP/IP
,SOAP
协议,HTTP
协议,SMTP
协议等
附:请求方式:
requests
模块为第三方支持库,需要手动安装pip install requests
GET 请求:将搜狗搜索内容爬取,并学习简单的反爬
import requests
url = "https://www.sogou.com/web?query=周杰伦" #保存网址字符串给变量,中文可能转码错误,手动打上去
#第10行处被拦截,可以将更多请求头信息补入,定义一个字典headers,将User-Agent写入字典,User-Agent通过抓包网页骨架中的Request Headers(请求头)找到,注意直接复制后Mozilla前会多一个空格,记得删除
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"}
#用get请求方式请求url,所有地址栏中的url都是get方式请求,将响应存入resp。第四行信息补充完成后,将字典写入headers参数,处理简单的反爬
resp = requests.get(url,headers=dict)
#print(resp) #打印resp,返回网页状态码,返回200正常
print(resp.text) #打印页面源代码,但爬虫被拦截了,前往第四行补充信息
resp.close() #关闭请求
可以进行一些小修改,做到更改搜索对象:
import requests
#手动输入搜索的内容
query=input("输入你要搜索的内容:")
#利用f-string,做到搜索内容更改
url = f"https://www.sogou.com/web?query={query}" #保存网址字符串给变量,中文可能转码错误,手动打上去
#第10行处被拦截,可以将更多请求头信息补入,定义一个字典headers,将User-Agent写入字典,User-Agent通过抓包网页骨架中的Request Headers(请求头)找到,注意直接复制后Mozilla前会多一个空格,记得删除
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"}
#用get请求方式请求url,所有地址栏中的url都是get方式请求,将响应存入resp。第四行信息补充完成后,将字典写入headers参数,处理简单的反爬
resp = requests.get(url,headers=dict)
#print(resp) #打印resp,返回网页状态码,返回200正常
print(resp.text) #打印页面源代码,但爬虫被拦截了,前往第四行补充信息
resp.close() #关闭请求
POST 请求:爬取百度翻译的结果
"""
打开百度翻译后按F12进入抓包工具,清除多余的文件,注意输入法切换为英文,输入英文单词后,翻译框下方有一个小列表
在抓包工具中通过preview预览尝试寻找列表的数据文件,发现sug文件为数据文件
打开sug文件的Headers,获取需要的信息:url地址,请求方式为POST
打开Payload,找对From Data,为POST传参数据,对于上个GET程序中利用f-string传入参数的方式就不灵了
"""
import requests
url = "https://fanyi.baidu.com/sug" #准备url,注意url为数据的url,即sug文件Headers的url
word = input("请输入你要翻译的英文:") #准备翻译的单词
dat = {"kw":word} #由于POST传参数据来源为From Data,所以按照From Data中的格式,将搜索数据改写入字典,此时可以通过变量更改数据
resp = requests.post(url,data=dat) #由于网页访问方式为POST,故使用POST访问,将dat传入data参数,即传入From Data。将响应存入resp
#print(resp.text) #输出发现文件有乱码,可以另外直接输出json文件
print(resp.json()) #将服务器返回的内容直接处理成json(),按照python字典方式输出
resp.close() #关闭请求
#总结,对于POST请求,发送的数据必须放在字典中,通过data参数进行传递
浏览器渲染的二次 GET
"""
豆瓣电影分类排行榜网页通过浏览器渲染,有两次数据传递
在抓包工具中选择筛选XHR类别(常表示二次请求数据),找到跟页面差不多的蕴含量大一些的XHR文件,就是页面的数据文件找到数据文件Headers:
查看url,通常网站url里有问号"?",问号前的是url,问号后的是参数,查看请求方式为GET方式
在Payload中有Query String Parameters(url问号后参数),
"""
import requests
url = "https://movie.douban.com/j/chart/top_list" #参数过长,可以重新封装url参数,url问号后参数部分可以删除
#重新封装参数。将抓包Query String Parameters的参数复制进字典,分别打双引号,加逗号
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"} #布置user-agent
resp = requests.get(url,params=param,headers=header) #将param的参数传入params(截止params)。将返回的响应存入resp
#print(resp.request.url) #输出按照参数重组后的url地址
#print(resp.text) #code 0,什么都没有,说明被反爬了
print(resp.json())
resp.close() #关闭请求
#反爬处理
#首先尝试修改user-agent
#print(resp.request.headers) #(补充)查看默认信息,user-agent
#获取浏览器抓包user-agent,准备(第20行),写入requests.get的参数
#成功拿到数据,但有乱码,将24行优化为25行,获取json文件
这两个着重说一下,写爬虫用的最多的就是惰性匹配
*?
表示尽可能少的让*
匹配东西
<h1>I Love You</h1>
<h1 align="right">I Love You</h1>
借此实现标题文字右对齐,其中,align
为属性,right
为属性值
<标签 属性="值" 属性="值">被标记的内容</标签>
<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
模块,re
模块记住几个常用功能就足够我们日常使用了:
import re #引入re模块
#findall:匹配字符串中所有的符合正则的内容
list = re.findall("\d+","我的电话号是10086,我朋友的电话是10010") #findall的结果是一个列表
print(list,"\n")
#列表效率低下,面对大量数据难以应对,按如下处理
#finditer:匹配字符串中所有的内容[返回的是迭代器],从迭代器中遍历拿到内容需要.group()函数
it = re.finditer("\d+","我的电话号是10086,我朋友的电话是10010")
#print(it)
for i in it:
print(i.group())
print()
#search返回的结果是match对象,那数据需要.group(),此外search全文检索,检索到一个就直接返回
s = re.search("\d+","我的电话号是10086,我朋友的电话是10010")
#print(s)
print(s.group(),"\n")
#match从头开始匹配,可以认为默认在正则前加了^符号,如下方10086前加一个非数字,则匹配为空
a = re.match("\d+","10086,我朋友的电话是10010")
print(a.group(),"\n")
#compile预加载正则表达式,能够提高一定的运行效率
obj = re.compile("\d+")
#此时obj即预加载\d+的正则,下次使用可以obj.函数,如下:
ret = obj.finditer("我的电话号是10086,我朋友的电话是10010")
#print(ret)
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) #re.S作用:让点.能匹配换行符
#<div class='部分都一样,后面不一样部分.*?代替,匹配后jay双引号后部分一样,一直到id=后单引号后不同,
#用\d或\d+或者.*?代替,后同理,略
result = obj1.finditer(s)
for it in result:
print(it.group())
print()
#从全部文本信息中提取想要的信息(在上述代码中修改)
#在要提取的文本.*?等正则符号处,用小括号包住,小括号前写?P<组名> ,最后在遍历的组括号(60行)写入这个组名
obj1 = re.compile("<div class='.*?'><span id='\d+'>(?P<gualudeng>.*?)</span></div>",re.S) #re.S作用:让点.能匹配换行符
#<div class='部分都一样,后面不一样部分.*?代替,匹配后jay双引号后部分一样,一直到id=后单引号后不同,
#用\d或\d+或者.*?代替,后同理,略
result = obj1.finditer(s)
for it in result:
print(it.group("gualudeng"))
print()
#数据在页面源代码中
#思路:拿到页面源代码,通过re正则提取我们想要的有效信息
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) #简单的提取源代码和反反爬
#print(resp.text) #检查页面源码
page_content = resp.text #保存源代码至变量
#解析数据
#正则表达式定位,建议找需要数据的上几层标签做定位
#<li>为上层标签,换行时的空白可能是换行可能是空格,使用.*?表示,继续匹配到下一行,后面多行都用.*?匹配,直接找到需要的title,在需要部分单独列组(),补充后面的截止部分(此处截止至</span>处),后略
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) #编写正则方法
#使用finditer进行正则筛选
result = obj.finditer(page_content)
#遍历result,得到数据
for it in result:
print("\n电影名:",it.group("title"),"\n年份:",it.group("year").strip(),"\n评分:",it.group("score")) #group中的名字均为正则中的组名, .strip()为去除空白(空格)
#将数据存入文件,建议存储为csv格式。引入csv模块,.csv文件默认以逗号进行数据分割
f = open("data.csv",mode="w",encoding="utf-8") #打开文件data.csv,没有文件自动创建,模式为r写入,打开格式为utf-8
csvwriter = csv.writer(f) #创建csvwriter,写入数据时写入f文件,注意写入数据格式应为字典
result = obj.finditer(page_content) #同18行
for it in result:
dic= it.groupdict() #创建字典,将上述20-21行数据整理进字典
dic["year"] = dic["year"].strip() #单独处理需要去掉空格的year组
csvwriter.writerow(dic.values()) #writerow为写入一行函数,括号()内为写入数据,写入的为字典的数据.values()
f.close() #关闭文件
print("over!")
#目前完成了top25的整理,而翻页数据只需要修改url后的参数即可,比如第二页url为https://movie.douban.com/top250?start=25&filter=
#由此得第一页参数start=0,第三页start=50,所以输出top250排行榜,可以此为方向研究
参考源代码:
"""
1、确认数据在页面源码中,定位到2022必看热片
2、从2022必看热片中提取到子页面链接地址
3、请求子页面的链接地址,拿到想要的下载地址
"""
import requests,re
main_url = "https://dytt89.com/" #主界面url
child_url_list = []
#原老版网站存在https加密,requests模块也有安全验证,所以会报错,可以使用verify=False关闭安全验证来解决,运行时最上部的警告意为“请求没有进行安全验证”。新版网站已取消
resp = requests.get(main_url , verify=False) #verify=False关闭安全验证
resp.encoding = "gb2312" #指定字符集编码
#print(resp.text) #输出乱码,需要重新编码,网页编码格式通常在源码charset处会写明,找到后补充上一行代码,更改默认编码
#定位提取ul里面的li
obj1 = re.compile('2022必看热片.*?<ul>(?P<ul>.*?)</ul>',re.S) #提取需要的部分
obj2 = re.compile("<a href='(?P<href>.*?)'",re.S) #提取a标签中的url链接
#开始筛选提取
result1 = obj1.finditer(resp.text) #第一次提取板块源码部分
for it in result1:
ul = it.group("ul") #存入ul
#print(ul) #检验输出
#html知识补充:在html中,a标签表示超链接,如:<a href='url'>周杰伦</a>,网页上显示周杰伦的超链接,跳转地址为href=后的url
#提取子页面链接(href后url)
result2 = obj2.finditer(ul) #第二次从板块源码部分提取url,但提取的url为参数,需要与main_url拼接
for itt in result2:
add = itt.group("href") #存入add
#print(add) #检验输出
child_url = main_url + add.strip("/") #拼接url,使用strip除去拼接处多余的一个/符号
#print(child_url) #检验输出
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"
#下两行仅为测试使用
#print(child_resp.text)
#break
result3 = obj3.search(child_resp.text)
print(result3.group("movie"))
print(result3.group("download"))
参考源代码:
python 的 bs4
模块为第三方模块,需要先安装,安装 cmd 语法如下:
pip install bs4
注:页面重构,下示例代码仅可参考,无法运行,网站改为浏览器渲染,使用 POST 请求
# 页面源代码中能找到数据,所以直接爬取,后使用bs4提取数据即可
import requests
import csv
from bs4 import BeautifulSoup
url = "http://www.xinfadi.com.cn/marketanalysis/0/list/1.shtml"
resp = requests.get(url)
# print(resp.text) #测试
# 准备需要写入的文件
f = open("菜价.csv", mode="w")
csvwriter = csv.writer(f)
# 解析数据,把页面源代码交给beautiful soup处理,生成bs4的对象
page = BeautifulSoup(resp.text, "html.parser") # 括号第二个参数指定html解析器
# 从bs4对象查找数据(find / find_all(标签 属性="值"))
# 查找内容。由于class是python关键字,所以写class_代替
table = page.find("table", class_="hq_table")
# print(table) #测试
# 得到的是表格,表格内每一行为tr标签,每一行内每列为td标签
# 再次筛选tr,拿到所有数据行,做切片,从1行开始切,去除0行的表头
trs = table.find_all("tr")[1:]
for tr in trs: # 每一行的数据进行遍历
tds = tr.find_all("td") # 拿到每行中的所有td
name = tds[0].text # .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
# print(name, low, avg, high, kind, set, date) #输出测试
csvwriter.writerow([name, low, avg, high, kind, set, date]) # 写入文件,需要列表
f.close()
print("over")
参考源代码:
# 1.拿到主页面的源代码,然后提取到子页面的链接地址,href
# 2.通过href拿到子页面的数据内容,提取图片的下载地址,img->src
# 3.下载图片
import requests
import time # 对应37行代码
from bs4 import BeautifulSoup
url = "https://umei.cc/bizhitupian/weimeibizhi"
resp = requests.get(url)
resp.encoding = "utf-8" # 解码处理
# print(resp.text) #测试
# 把源代码交给bs4
main_page = BeautifulSoup(resp.text, "html.parser")
# 取得typelist后提取a标签
alist = main_page.find("div", class_="TypeList").find_all("a")
# print(alist) #测试
for a in alist: # 循环遍历每一个a标签
# print(a.get("href")) #测试,直接通过get就可以得到属性值
href = a.get("href")
# 至此任务1完成。进行任务2
# 拿到子页面源代码
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_resp.content # content获取到的是字节,写回到文件就是图片
img_name = src.split("/")[-1] # 图片命名,对src链接以"/"切割,并取最后一部分命名
with open(img_name, mode="wb") as f: # wb写入二进制图片
f.write(img_resp.content) # 写入图片
print("part success!", img_name)
time.sleep(1) # 防止访问过于频繁被封ip,休息1秒钟
print("all over!")
参考源代码:
python 的 lxml
模块为第三方模块,需要先安装,安装 cmd 语法如下:
pip install lxml
from lxml import etree
xml = """......""" # 将XML文档存入变量,(此处省略,本程序无法直接运行)
tree = etree.XML(xml) # 生成etree的XML文档
# result = tree.xpath("/book") # xpath查找book节点,"/"表示层级关系,第一个"/"是根节点
result1 = tree.xpath("/book/name/text()") # text()表示获取被标记的内容
print(result1)
# 双斜杠"//"表示范围内跨层级搜索(全局搜索)
result2 = tree.xpath("/book/author//nick/text()")
# xpath中"*"符号为通配符,表示任意,同正则表达式的"."
result3 = tree.xpath("/book/author/*/nick/text()")
headers
了,header
为 HTTP 协议中的请求头,一般存放一些和请求内容无关的数据,有时也会存放一些安全验证信息,比如常见的User-Agent
,token
,cookie
等
requests
发送的请求,我们可以把请求头信息放在 headers 中.也可以单独进行存放,最终由 requests 自动帮我们拼接成完整的 http 请求头
Initiator
中request call back
项记录了网站调用的 JS 栈,从下往上按时间顺序排列。点击可以进入 JS 源码,点击窗口左下方的大括号可以对源码进行缩进排版,找到需要的发送行设置断点,利用断点调试找到需要的信息,可以借此得到一些网站的加密过程或其他源码(涉及逆向 JS,较为复杂)def func():
for i in range(1000):
print("func", i)
if __name__ == "__main__":
func()
for j in range(1000):
print("main", j)
一个简单的线性单线程程序,主函数中,func
函数执行完毕后才会执行主函数的for
循环
Thread
类:from threading import Thread # 导入线程的类
def func():
for i in range(1000):
print("func", i)
if __name__ == "__main__":
t = Thread(target=func) # 创建一个线程类的对象,并且target=告诉程序这个线程执行的话会执行谁,为线程安排任务
t.start() # 设置多线程状态为可以执行状态,具体的执行时间由CPU决定
for j in range(1000):
print("main", j)
Thread
的class
类:from threading import Thread
class MyThread(Thread): # 继承Thread
def run(self): # 固定的 # 当线程被设置可以执行之后,被执行的就是run()
for i in range(1000):
print("子线程", i)
if __name__ == "__main__":
t = MyThread()
# t.run() #千万不能使用t.run,否则就是类方法的调用!--->单线程
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__":
# 在Thread函数中,添加args进行传参,且args接收的数据类型必须是元组
# 注意,元组内只有一个元素的时候需要加逗号
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
# 注:ThreadPoolExecutor为线程池,ProcessPoolExecutor为进程池,按需引入
def fn(name):
for i in range(1000):
print(name, i)
if __name__ == "__main__":
# 创建线程池
# 创建一个由50个线程组成的线程池,其中ThreadPoolExecutor的参数控制线程数量
with ThreadPoolExecutor(50) as t:
# 表示100个任务的for循环
for i in range(100):
# 给线程提交任务
t.submit(fn, name=f"线程{i}")
# 等待线程池的内容全部完成才会执行(守护)
print("over")
import time
def func():
print("123")
time.sleep(3) # 让当前线程处于阻塞状态,CPU不为此程序工作
print("456")
if __name__ == "__main__":
func()
# 执行input()时,程序也是处于阻塞状态
# requests.get()请求等待过程中,程序也是处于阻塞状态
# 一般情况下,当程序处于IO操作时,线程都会处于阻塞状态
IO操作
的时候,可以选择性的切换到其他任务上
在微观上是一个任务一个任务的进行切换,在宏观上我们能看见的是多个任务一起共同执行
这种操作称为多任务异步操作
上方所讲的一切,都是在单线程的条件下import asyncio
# 用async定义异步协程函数
async def func():
print("你好,我叫塞丽娜")
if __name__ == "__main__":
#此时的函数是异步协程函数,此时函数执行得到的是一个协程对象
g = func()
# print(g) # 测试
asyncio.run(func) # 协程程序运行需要asyncio模块的支持
import asyncio
import time
async def func1():
print("你好,我叫潘金莲")
# time.sleep(3) # 当程序出现同步操作时,异步就中断了
await asyncio.sleep(3) # 异步模块的sleep,使用await挂起,切到其他任务
print("你好,我叫潘金莲")
async def func2():
print("你好,我叫王建国")
# time.sleep(2)
await asyncio.sleep(2)
print("你好,我叫王建国")
async def func3():
print("你好,我叫李雪琴")
# time.sleep(4)
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():
# 第一种写法
# f1 = func1()
# await f1 #await通常放在协程对象前面
# 后略
#第二种写法(推荐)
tasks_=[
func1(),func2(),func3()
]
await asyncio.wait(tasks_)
if __name__ == '__main__':
asyncio.run(main())
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())
- 发送请求时,原先的`requests.get()`是一个同步操作,会将异步程序转为同步,需要换成**异步请求操作**
python 的 aiohttp
模块为第三方模块,需要先安装,安装 cmd 语法如下:
pip install aiohttp
import asyncio
import aiohttp
urls = [
"photo_url1",
"photo_url2",
"photo_url3"
]
async def aiodownload(url):
# 发送请求,得到图片内容,保存到文件
# 得到异步会话
# s = aiohttp.ClientSession() # 等价于原来的requests模块,例如可使用s.get
# 使用with上下文管理器,可以省去手动session.close()
async with aiohttp.ClientSession() as session:
# 发送请求,得到resp
async with session.get(url) as resp:
# 此处为读取图片,所以使用content
# resp.content.read() # 等价于原先的resp.content,此处需要多.read()读取
# resp.text() # 读取文本,需要多一个()
# resp.json() # 同原先相同
# 写入文件
with open("文件名(可以按url地址切割存入变量)", mode="wb") as f:
# IO操作,需要await挂起
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())
# 所有章节内容的url(章节名称,cid)
# https://dushu.baidu.com/api/pc/getCatalog?data={"book_id":"4306063500"}
# 章节内部的具体内容
# https://dushu.baidu.com/api/pc/getChapterContent?data={"book_id":"4306063500","cid":"4306063500|1569782244","need_bookinfo":1}
import requests
import asyncio
import aiohttp
import aiofiles
import json
# 1.同步操作,访问getCatalog,拿到所有章节的cid和名称
# 2.异步操作:访问getChapterContent,拿到小说内容并下载
async def aiodownload(cid, book_id, title):
# 准备参数,作为json代码
data = {
"book_id": f"{book_id}",
"cid": f"{book_id}|{cid}",
"need_bookinfo": 1
}
# 转换json为字符串
data = json.dumps(data)
# 拼接url
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()
# dic["data"]["novel"]["content"] #小说的内容
# 利用aiofiles异步写入文件
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)
# print(resp.text) # 测试
dic = resp.json()
# 准备异步的空列表
tasks_ = []
for item in dic["data"]["novel"]["items"]: # item对应每个章节的名称和cid
title = item["title"]
cid = item["cid"]
# print(cid,title) # 测试
# 每一个cid就是一个url,准备异步任务
tasks_.append(aiodownload(cid, book_id, title))
await asyncio.wait(tasks_)
if __name__ == '__main__':
# 将book_id提取为单独的变量备用
book_id = "4306063500"
url = 'https://dushu.baidu.com/api/pc/getCatalog?data={"book_id":"' + book_id + '"}'
asyncio.run(getCatalog(url))
from selenium.webdriver import Chrome
# 1.创建浏览器对象
web = Chrome()
# 2.打开一个网址
web.get("http://www.baidu.com")
print(web.title)
from selenium.webdriver import Chrome
from selenium.webdriver.common.keys import Keys
import time
web = Chrome()
web.get("http://lagou.com")
# 点击页面中的某个元素,通过在页面检查元素,复制xpath
el = web.find_element_by_xpath('//*[@id="changeCityBox"]/p[1]/a') # 找到元素
el.click() # 点击元素
# 也可以直接写为web.find_element_by_xpath('//*[@id="changeCityBox"]/p[1]/a').click()
# 可以通过by后不同的查找方式查找,如div标签这种页面中存在很多的元素,可以通过find_elements全部获取
# web.find_elements_by_tag_name("div")
# 防止刷新速度慢,暂停1秒
time.sleep(1)
# 找到输入框,输入python ---> 输入回车/点击搜索
# 此处实现输入回车,找到输入框,使用.send_keys()输入内容
# 键盘回车通过第二行的包中的Keys模块实现,点进Keys可以查看所有能实现的键盘按键
web.find_element_by_xpath('//*[@id="search_input"]').send_keys("python", Keys.ENTER)
time.sleep(1)
# 查找存放数据的位置,进行数据提取(注:此处代码由于网页重构已失效,无法运行!)
# 找到存放数据的所有li,注意获取多个最后li的[]索引要删除
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()
# 如何进入到新窗口进行提取
# 注意,即使浏览器已经切换新窗口,在selenium的眼中,新出现的窗口默认是不切换的(未被选中)
# 切换窗口,使用window_handles[-1]选中最后一个窗口选项卡
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()
# 页面中遇到iframe怎么处理
web.get("https://www.91kanju.com/vod-play/541-2-1.html")
# 要处理iframe,必须先得到iframe,然后切换视角到iframe,才能拿数据
# 定位到iframe
iframe = web.find_element_by_xpath('//*[@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)
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)
‘//*[@id=“player_iframe”]’)
web.switch_to.frame(iframe)
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)