目录
简介
爬虫在使用场景中的分类
反爬机制
反反爬策略
robots.txt协议
基本概念
http协议
常用请求头信息
常用响应头信息
https协议
加密方式
requests模块
作用
如何使用
环境安装
实战编码
爬取搜狗首页的页面数据
简易网页采集器
破解百度翻译
爬取豆瓣电影分类排行榜
爬取肯德基餐厅查询
聚焦爬虫
简介
数据解析分类:
数据解析原理概述
正则表达式
豆瓣电影Top250
电影天堂https://www.dytt89.com/
Bs4解析
新发地http://www.xinfadi.com.cn/priceDetail.html
唯美壁纸
Xpath
猪八戒网
https://www.zbj.com/search/f?type=new&kw=saas
requests进阶概述
处理cookie登录小说网
防盗链抓取梨视频
代理
抓取网易云音乐评论信息
给爬虫提速
多线程
多进程
线程池
新发地
协程
异步协程aiohttp模块
扒光一部小说
综合训练:抓取一部视频
Selenium
概述
步骤
打开和关闭浏览器
获取网址
寻找节点
输入信息
点击按钮
selenium——以LoL数据网站opgg为例
可执行程序
selenium——利用鼠标移动操作巧妙爬取highcharts动态图表
问题:大部分情况卡在登录页面,然后报错(偶尔成功)
如何操作鼠标
有关移动操作
简介
爬虫在使用场景中的分类
- 通用爬虫:抓取系统的重要组成部分。抓取的是一整张页面数据
- 聚焦爬虫:建立在通用爬虫的基础之上。抓取的是页面中特定的局部内容
- 增量式爬虫:检测网站中数据更新的情况。只会抓取网站中最新更新出来的数据
反爬机制
门户网站,可以通过制定相应的策略或者技术手段,防止爬虫程序进行网站数据的爬取
反反爬策略
爬虫程序可以通过制定相关的策略或者技术手段,破解门户中具备的反爬机制,从而可以获取门户网站中相关的数据
robots.txt协议
君子协议。明确规定网站中哪些数据可以被爬虫爬取,哪些数据不可以被爬取。
基本概念
http协议
服务器和客户端进行数据交互的一种形式
常用请求头信息
User-Agent:请求载体的身份标识
Connection:请求完毕后,是断开连接还是保持连接
常用响应头信息
Content-Type:服务器响应回客户端的数据类型
https协议
安全的超文本传输协议
加密方式
- 对称密钥加密 (不安全,django框架中间件可以拦截,密文和密钥一起发给服务器)
- 非对称密钥加密(服务器将公钥发送给客户端-客户端拿到公钥对发送信息加密-服务器自己私钥解密)但是无法保证拿到的公钥是否为服务端发送
- 证书密钥加密
requests模块
python中原生的一款基于网络请求的模块,功能非常强大,简单便捷,效率极高
作用
模拟浏览器发请求
如何使用
- 指定url
- 发起请求
- 获取响应数据
- 持久化存储
环境安装
pip install requests
实战编码
爬取搜狗首页的页面数据
import requestsif __name__=="__main__":#指定urlurl='https://www.sogou.com/'#发起请求response=requests.get(url=url)#获取响应数据,text返回的是字符串形式的响应数据page_text=response.textprint(page_text)#持久化存储with open('./sogou.html','w',encoding='utf-8') as fp:fp.write(page_text)
简易网页采集器
import requests#UA检测:门户网站的服务器会检测对应请求的载体身份标识,如果检测到请求的载体身份标识为某一款浏览器#说明该请求是一个正常的请求,但是,如果检测到请求的载体身份标识不是基于某一款浏览器的,则表示爬虫#UA:User-Agent(请求载体的身份标识)if __name__=="__main__":headers={"User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54'}url='https://www.sogou.com/web'#处理url携带的参数:封装到字典中kw=input('enter a word')param={'query':kw}#对指定的url发起的请求对应的url是携带参数的,并且请求过程中处理了参数response=requests.get(url=url,params=param,headers=headers)page_text=response.textfileName=kw+'.html'with open(fileName,'w',encoding='utf-8') as fp:fp.write(page_text)print(fileName,'保存成功')
破解百度翻译
post请求(携带了参数)
响应数据是一组json数据
import requests,json#UA检测:门户网站的服务器会检测对应请求的载体身份标识,如果检测到请求的载体身份标识为某一款浏览器#说明该请求是一个正常的请求,但是,如果检测到请求的载体身份标识不是基于某一款浏览器的,则表示爬虫#UA:User-Agent(请求载体的身份标识)if __name__=="__main__":headers={"User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54'}post_url="https://fanyi.baidu.com/sug"#post请求参数处理(同get请求一致)word=input('enter a word')data={'kw':word}response=requests.post(url=post_url,data=data,headers=headers)#获取响应数据:json()方法返回的是obj(如果确认响应数据是json类型的,才可以使用json())dic_obj=response.json()print(response.text)print(dic_obj)#持久化存储fileName=word+'.json'with open(fileName,'w',encoding='utf-8') as fp:json.dump(dic_obj, fp=fp, ensure_ascii=False)# 中文不能使用ascii编码print("OVER!!")
{“errno”:0,”data”:[{“k”:”pig”,”v”:”n. \u732a; \u732a\u8089; \u4ee4\u4eba\u4e0d\u5feb\uff08\u6216\u8ba8\u538c\uff09\u7684\u4eba; \u91d1\u5c5e\u5757\uff08\u952d\uff09 vi. \u751f\u5c0f\u732a; \u50cf\u732a\u4e00\u6837\u8fc7\u6d3b; \u4e3e\u6b62\u50cf”},{“k”:”PIG”,”v”:”abbr. PendulousIntegratingGyro\u6446\u5f0f\u79ef\u5206\u9640\u87ba\u4eea”},{“k”:”pIg”,”v”:”abbr. polymeric immunoglobulin \u805a\u5408\u514d\u75ab\u7403\u86cb\u767d”},{“k”:”PIg”,”v”:”\u591a\u514b\u9686\u514d\u75ab\u7403\u86cb\u767d”},{“k”:”pigg”,”v”:”n. \u732a\uff0c\u732a\u8089\uff0c\u8d2a\u5a6a\u7684\u4eba v. \u751f\u5c0f\u732a\uff0c\u8d2a\u5a6a\u5730\u5403″}]}
{‘errno’: 0, ‘data’: [{‘k’: ‘pig’, ‘v’: ‘n. 猪; 猪肉; 令人不快(或讨厌)的人; 金属块(锭) vi. 生小猪; 像猪一样过活; 举止像’}, {‘k’: ‘PIG’, ‘v’: ‘abbr. PendulousIntegratingGyro摆式积分陀螺仪’}, {‘k’: ‘pIg’, ‘v’: ‘abbr. polymeric immunoglobulin 聚合免疫球蛋白’}, {‘k’: ‘PIg’, ‘v’: ‘多克隆免疫球蛋白’}, {‘k’: ‘pigg’, ‘v’: ‘n. 猪,猪肉,贪婪的人 v. 生小猪,贪婪地吃’}]}
OVER!!
爬取豆瓣电影分类排行榜
import requestsimport jsonheaders={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54'}url='https://movie.douban.com/j/chart/top_list" />
爬取肯德基餐厅查询
肯德基餐厅信息查询 (kfc.com.cn)
import requests,jsonheaders={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54"}url="http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword"param={"cname":"","pid":"","keyword": "北京","pageIndex":"1","pageSize": "10"}response=requests.post(url=url,data=param,headers=headers)page_text=response.textprint(page_text)with open("./肯德基.txt",'w',encoding='utf-8') as fp:fp.write(page_text)
聚焦爬虫
简介
爬取页面中指定的页面内容。
编码流程:
- 指定url
- 发起请求
- 获取相应数据
- 数据解析
- 持久化存储
数据解析分类:
- 正则
- bs4
- xpath(****)
数据解析原理概述
- 解析的局部的文本内容都会在标签之间或者标签对应的属性中进行存储
- 1.进行指定标签的定位
- 2.标签或者标签对应的属性中存储的数据值进行提取(解析)
正则表达式
豆瓣电影Top250
https://movie.douban.com/top250
import requestsimport reurl="https://movie.douban.com/top250"headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54"}response=requests.get(url=url,headers=headers)content=response.text# print(content)#解析数据#预加载正则表达式#re.S用法 re.S的作用: 不使用re.S时,则只在每一行内进行匹配,如果存在一行没有,就换下一行重新开始,使用re.S参数以后,正则表达式会将这个字符串看做整体,在整体中进行匹配,一般在爬虫项目中会经常用到。obj=re.compile(r'.*?.*?(?P.*?)',re.S)result=obj.finditer(content)for i in result:print(i.group("name"))
D:\python\python.exe "D:\python project\pythonProject2\main.py"
肖申克的救赎
霸王别姬
阿甘正传
泰坦尼克号
这个杀手不太冷
美丽人生
千与千寻
辛德勒的名单
盗梦空间
星际穿越
楚门的世界
忠犬八公的故事
海上钢琴师
三傻大闹宝莱坞
放牛班的春天
机器人总动员
无间道
疯狂动物城
控方证人
大话西游之大圣娶亲
熔炉
教父
当幸福来敲门
触不可及
怦然心动Process finished with exit code 0
import requestsimport reimport csvheaders = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54"}print("请输入您要爬取的页数")num=input()num=int(num)for i in range(num):i=i*25print(i)url = "https://movie.douban.com/top250?start={}&filter=".format(i)print(url)response=requests.get(url=url,headers=headers)content=response.text# print(content)#解析数据#预加载正则表达式#re.S用法 re.S的作用: 不使用re.S时,则只在每一行内进行匹配,如果存在一行没有,就换下一行重新开始,使用re.S参数以后,正则表达式会将这个字符串看做整体,在整体中进行匹配,一般在爬虫项目中会经常用到。obj=re.compile(r'.*?.*?(?P.*?)' r'.*?.*?
(?P.*?) ' r'.*? ',re.S)result=obj.finditer(content)#for i in result:# print(i.group("name"))# print(i.group("year").strip())# print(i.group("average"))# dic=i.groupdict()# dic['year']=dic['year'].strip()with open("data.csv","a",encoding="utf-8") as f:writer=csv.writer(f)for i in result:dic=i.groupdict()dic['year']=dic['year'].strip()writer.writerow(dic.values())
电影天堂https://www.dytt89.com/
#1.定位到2023必看片#2.从2023必看篇中提取到页面的链接地址#3.请求子页面的链接地址,拿到我们想要的下载地址import reimport requestsdomain="https://www.dytt89.com/"headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54"}resp=requests.get(url=domain,headers=headers,verify=False)#去掉安全验证resp.encoding="gb2312"#指定字符集obj1=re.compile(r"2023必看热片.*" />.*?)'.*?",re.S)for it in result1:ul=it.group('ul')# print(ul)#提取子链接result2=obj2.finditer(ul)for i in result2: li=i.group('li') print(li)
/i/107232.html
/i/105577.html
/i/107374.html
/i/107262.html
/i/102985.html
/i/106713.html
/i/103295.html
/i/107097.html
/i/107090.html
/i/107046.html
/i/105313.html
/i/106931.html
/i/106888.html
Bs4解析
新发地http://www.xinfadi.com.cn/priceDetail.html
这个检查源代码会显示这,但是查看源代码就不显示,判断是动态加载
唯美壁纸
https://www.umei.cc/bizhitupian/weimeibizhi/
#1.拿到主页面的源代码,然后提取到子页面的链接地址,href#2.通过href拿到子页面的内容,从子页面中找到图片的下载地址 img->src#3.下载地址import requestsfrom bs4 import BeautifulSoupurl="https://www.umei.cc/bizhitupian/weimeibizhi"headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54"}resp=requests.get(url=url,headers=headers)resp.encoding='utf-8'page=resp.text# print(page)main_page = BeautifulSoup(page, "html.parser")div_list = main_page.find_all("div", class_="img")visited_links = []for div in div_list:alist = div.find_all("a")for a in alist:href="https://www.umei.cc/"+a.get('href')if href not in visited_links:# 检查是否已经访问过visited_links.append(href)# print(href)#拿到子页面的源代码child_page_resp=requests.get(url=href,headers=headers)child_page_resp.encoding='utf-8'child_page_text=child_page_resp.text#从子页面中拿到图片的下载路径second_page=BeautifulSoup(child_page_text,"html.parser")div_list1=second_page.find("div",class_="big-pic").find("img")src=div_list1.get('src')#下载图片img_resp=requests.get(src)img_name=src.split("/")[-1]#拿到url中的最后一个/以后的内容# img_resp.contentwith open(img_name,mode="wb") as f:f.write(img_resp.content)#图片内容写入文件print("over!!!",img_name)print("all over")
Xpath
- xpath是在XML文档中搜索内容的一门语言
- html是xml的一个子集
- pip install lxml
猪八戒网
https://www.zbj.com/search/f?type=new&kw=saas
#拿到页面源代码#提取和解析数据import requestsfrom lxml import etreeurl="https://beijing.zbj.com/search/f" />
2998
['微信游戏saas商城公众号java前端小程序后端定制开发']
1308
['工业物联网3D数字孪生】智慧园区java软件开发定制saas']
1980
['宠物平台app/微信养宠物小程序saas网页定制二次开发']
20000
['平台开发餐饮', '软件开发网站管理物流医疗工业']
30000
['平台开发餐饮', '软件开发网站管理物流医疗工业']
30000
['平台开发餐饮', '软件开发网站管理物流医疗工业']
999
['微信小程序定制作开发h5', '公众号商城分销团购外卖']
3588
['微信小程序定制开发招聘模板教育考试打车加油外包']
1299
['软件开发网站定制OA系统CRM系统', '平台ERP系统']
3588
['微信抖音', '模板小程序成品分销商城h5源码定制开发']
Unable to extract price information for this provider.
Unable to extract price information for this provider.
Unable to extract price information for this provider.
Unable to extract price information for this provider.
我遇到的问题:
- 我个人怀疑这里有反爬机制,因为生成的内容有的时候不一样
- 我发现检查源代码的内容与查看源代码的内容不一致,导致复制xpath绝对路径会出现空列表
requests进阶概述
处理cookie登录小说网
https://www.17k.com/
- 登录->得到cookie
- 带着cookie去请求到书架url->书架上的内容
- 必须得把上面的两个操作连起来
- 我们可以使用session进行请求->session可以认为是一连串的请求,在这个过程中的cookie不会丢失
https://passport.17k.com/ck/user/login
https://user.17k.com/ck/author/shelf?page=1&appKey=2406394919
import requests#会话session=requests.session()#登录url="https://passport.17k.com/ck/user/login"data = {'loginName': '小木aaaaaa','password': '15175857475a'}session.post(url,data=data)# print(resp.text)# print(resp.cookies)#2.拿到书架上的数据resp=session.get('https://user.17k.com/ck/author/shelf?page=1&appKey=2406394919')print(resp.json())
防盗链抓取梨视频
https://www.pearvideo/
这里检查源代码就和查看页面源代码内容有些出入——动态加载
上面图片预览中的地址 ,这个地址打不开https://video.pearvideo.com/mp4/adshort/20210916/1681456167649-15768660_adpkg-ad_hd.mp4
检查源代码的地址:https://video.pearvideo.com/mp4/adshort/20210916/cont-1741775-15768660_adpkg-ad_hd.mp4
import requests#1.拿到contId#2.拿到videoStatus返回的json.->srcURL#3.srcURL里面的内容进行修正#4.下载视频url="https://www.pearvideo.com/video_1741775"headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.39",#防盗链:溯源,当前请求的上一级是谁"Referer":url}contId=url.split("_")[1]videoStatueUrl=f"https://www.pearvideo.com/videoStatus.jsp" />
代理
https://www.zdaye.com/Free/
import requests#61.160.212.99:8111proxies={"https":"https://223.108.49.50:3128"}resp=requests.get("https://www.baidu.com",proxies=proxies)resp.encoding="utf-8"print(resp.text)
遇到的问题:代理不能用
抓取网易云音乐评论信息
https://music.163.com/#/playlist?id=2821115454
- 找到未加密的参数
- 想办法把参数进行加密(必须参考网易的逻辑),params,encSecKey
- 请求到网易,拿到评论信息
import requests, jsonfrom Crypto.Cipher import AESfrom base64 import b64encodeurl = "https://music.163.com/weapi/comment/resource/comments/get" /> d; d += 1)#循环16次e = Math.random() * b.length,#随机数e = Math.floor(e),#取整c += b.charAt(e);#取字符串中的xxx位return c}function b(a, b) {var c = CryptoJS.enc.Utf8.parse(b), d = CryptoJS.enc.Utf8.parse("0102030405060708"), e = CryptoJS.enc.Utf8.parse(a), f = CryptoJS.AES.encrypt(e, c, {iv: d,mode: CryptoJS.mode.CBC});return f.toString()}function c(a, b, c) {#c里面不产生随机数var d, e;return setMaxDigits(131),d = new RSAKeyPair(b,"",c),e = encryptedString(d, a)}function d(d, e, f, g) {#确定里面的每个参数 #d:数据 e:010001 #f:'00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'#g:'0CoJUm6Qyw8W8jud'var h = {}, i = a(16);#i就是一个16位的随机值,把return h.encText = b(d, g),h.encText = b(h.encText, i),#返回的就是paramsh.encSecKey = c(i, e, f),#得到的是encSecKey,h"""encSecKey = "7b6b13e32326f18111136e910ac9162d0bbe63af52dcaf11f9052085a58aaa5f4313d178736dc0934d04c806e73436f11c9fa3a9f6858bc86eae5c71d39347c2d7745ff30e3af7e5ae947605e4ec80131e0ed48e7a6464b1f55f274b7131ece470f5b0b454939a044020e918f140f17c490b0646365e65c33e21be6a08a6a37f"f = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'g = '0CoJUm6Qyw8W8jud'e = "010001 "i = "RGjaSLQLvktUK761"def get_encSecKey():return encSecKeydef get_params(data):first = enc_params(data, g)second = enc_params(first, i)return seconddef to_16(data):pad=16-len(data)%16data+=chr(pad)*padreturndatadef enc_params(data, key):iv = "0102030405060708"data=to_16(data)aes = AES.new(key=key.encode("utf-8"), IV=iv.encode('utf-8'), mode=AES.MODE_CBC)bs = aes.encrypt(data.encode("utf-8"))#加密,加密的内容的长度必须是16的倍数return str(b64encode(bs), "utf-8")# 转化成字符串返回# 处理加密过程resp = requests.post(url, data={"params": get_params(json.dumps(data)),"encSecKey": get_encSecKey()})print(resp.text)
给爬虫提速
多线程
进程是资源单位,每一个进程至少有一个线程
线程是执行单位
多进程
线程池
一次性开辟一些线程,我们用户直接给线程池提交任务,线程任务的调度交给线程池来完成
#线程池:一次性开辟一些线程,我们用户直接给线程池子提交任务,线程任务的调度交给线程池来完成from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutordef 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("123")
新发地
http://www.xinfadi.com.cn/priceDetail.html
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutorimport requests,json#1.如何提取单个页面的数据#2.上线程池,多个页面同时抓取headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.39",}def download_one_page(url,i):#拿到页面源代码data={"limit": 20,"current": i,"pubDateStartTime":"","pubDateEndTime":"","prodPcatid":"","prodCatid":"","prodName":"",}resp=requests.post(url,data=data,headers=headers)content=resp.json()print(content)if __name__ == '__main__':url="http://www.xinfadi.com.cn/getPriceData.html"with ThreadPoolExecutor(50) as t: for i in range(1,6): t.submit(download_one_page,url,i)
协程
time.sleep(3)#让当前的线程处于阻塞状态,cpu是不为我工作的
协程:当程序遇见了IO操作的时候,可以选择性的切换到其他任务上
在微观上是一个任务一个任务的进行切换,切换条件一般就是IO操作
在宏观上,我们看到的其实是多个任务一起执行
多任务异步操作
上方所讲的一切都是在单线程的条件下
#python编写协程的程序import asyncio,time# async def func():# print("hello world")# if __name__=='__main__':# g=func()# asyncio.run(g)#协程程序运行需要asyncio模块的支持async def func1():print("你好啊,我叫小猪佩奇")await asyncio.sleep(3)print("你好啊,我叫小猪佩奇")async def func2():print("你好啊,我叫卡布达")# time.sleep(2)#当程序出现了同步操作的时候,异步就中断了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)
你好啊,我叫小猪佩奇
你好啊,我叫卡布达
你好啊,我叫葫芦娃
你好啊,我叫卡布达
你好啊,我叫小猪佩奇
你好啊,我叫葫芦娃
4.011149644851685
import asyncio,timeasync def func1():print("你好啊,我叫小猪佩奇")await asyncio.sleep(3)print("你好啊,我叫小猪佩奇")async def func2():print("你好啊,我叫卡布达")# time.sleep(2)#当程序出现了同步操作的时候,异步就中断了await asyncio.sleep(2)#异步操作代码print("你好啊,我叫卡布达")async def func3():print("你好啊,我叫葫芦娃")await asyncio.sleep(4)print("你好啊,我叫葫芦娃")async def main():#第一种写法#f1=func1()#await f1一般await挂起操作放在协程对象前面#第二种写法(推荐)tasks=[asyncio.create_task(func1()),asyncio.create_task(func2()),asyncio.create_task(func3()),]await asyncio.wait(tasks)if __name__ == '__main__':t1=time.time()asyncio.run(main())t2=time.time()print(t2-t1)
异步协程aiohttp模块
#requests.get() 同步的代码->异步操作aiohttp#pip install aiohttpimport asyncioimport aiohttpurls=["http://kr.shanghai-jiuxin.com/file/bizhi/20220928/by12mnrxl5j.jpg","http://kr.shanghai-jiuxin.com/file/bizhi/20220928/pckme50aodn.jpg","http://kr.shanghai-jiuxin.com/file/bizhi/20220928/ultvo5cq2uw.jpg"]asyncdef aiodownload(url):#s=aiohttp.ClientSession()#相当与requests#发送请求#得到图片的内容#保存到文件name=url.rsplit("/",1)[1] #切取一次取第0个async with aiohttp.ClientSession() as session:async with session.get(url) as resp:#写入文件with open(name,mode="wb") as f:f.write(await resp.content.read())#读取内容是异步的,需要await挂起,rsp.text()async def main():tasks=[]for url in urls:tasks.append(aiodownload(url))awaitasyncio.wait(tasks)if __name__ == '__main__':asyncio.run(main())
扒光一部小说
西游记
记录请求的第一个url
综合训练:抓取一部视频
#一般的视频网站是怎么做的?#用户上传->转码(把视频做处理)->切片处理(把单个文件进行拆分)#用户在进行拉动进度条的时候#需要一个文件记录:1.视频播放顺序,2.视频存放路径"""想要抓取一个视频:1.找到m3u8(各种手段)2.通过m3u8下载ts文件3.可以通过各种手段(不仅是编程手段),把ts文件合并成一个mp4文件"""
Selenium
概述
- 网页浏览器的模拟器,通常用来做网页测试
- 直观、简单:直接模拟用户的行为,用户加载网页获取网页源码
- 与scrapy结合
- 多种web-driver:phantomjs,chrome....
- 缺点:
- 易识别
- 易崩溃
- 不易做成可执行程序
步骤
安装Google浏览器,以及对应版本的驱动器ChromeDriver,配置环境变量
- https://chromedriver.chromium.org/downloads
- pip install selenium
phantomjs
https://phantomjs.org/download.html
- 解压之后得到一个exe文件,放到和python.exe同目录下
打开和关闭浏览器
browser=selenium.webdriver.Chrome()#打开谷歌浏览器browser.close()
获取网址
browser.get(url)
寻找节点
#寻找单节点node = browser.find_element_by_xpath("//span[@style='user-select;auto']")#寻找多节点node = browser.find_elements_by_xpath("//span[@style='user-select;auto']")
输入信息
input=browser.find_element_by_xpath("//input")input.send_keys("青")
点击按钮
button=browser.find_element_by_xpath('')button.click()
selenium——以LoL数据网站opgg为例
下载xpath helper插件
https://www.op.gg/champions/darius/top/counters?region=global&tier=platinum_plus
from selenium import webdriverimport seleniumimport timefrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support import uifrom selenium.webdriver.chrome.options import Optionschrome_options=Options()#增加无头chrome_options.add_argument("--headless")chrome_options.add_argument("--disable-gpu")#防止被网站识别chrome_options.add_experimental_option('excludeSwitches',['enable-automation'])wait_time=5#用户输入position=input("请输入您想查询的位置")hero=input("请输入您要查询的英雄")#构造网址url=f"https://www.op.gg/champions/{hero}/{position}/counters"#打开浏览器browser=webdriver.Chrome(chrome_options=chrome_options,executable_path=r"phantomjs-2.1.1-windows\bin")#browser.maximize_window() 最大化browser.get(url)browser.implicitly_wait(10)#寻找按钮多节点wait=ui.WebDriverWait(browser,wait_time)try:wait.until(lambda driver:driver.find_elements(By.XPATH,r'//*[@id="content-container"]/aside/div[1]/div[2]/div/table/tbody/tr/td[2]/div/div'))except Exception as error1:print(error1)buttons=browser.find_elements(By.XPATH,r'//*[@id="content-container"]/aside/div[1]/div[2]/div/table/tbody/tr/td[2]/div/div')#遍历每一个按钮节点for button in buttons:# 点击按钮browser.execute_script("arguments[0].click();", button)# 寻找表格的最左列time.sleep(5)col = browser.find_elements(By.XPATH, r'//*[@id="content-container"]/main/div[1]/ul/li/div/div/div[1]/div')print(button.text, col[0].text, col[5].text)
可执行程序
- 打开cmd窗口
- pip install pyinstaller
- pyinstaller -F main.py
selenium——利用鼠标移动操作巧妙爬取highcharts动态图表
https://robo.datayes.com/v2/stock/002475/information#STOCK_POPULAR_FEELINGS
问题:大部分情况卡在登录页面,然后报错(偶尔成功)
如何操作鼠标
from selenium.wevdriver.common.action_chains import ActionChainsbrowser=webdriver.Chrome()#进行链式鼠标操作action=ActionChains(browser)action.(各种操作)action.perform
有关移动操作
from selenium.wevdriver.common.action_chains import ActionChainsbrowser=webdriver.Chrome()#进行链式鼠标操作action=ActionChains(browser)action.move_by_offset(xasis,yasis)#第一次是绝对坐标,第二次是相对坐标
from selenium import webdriverimport seleniumfrom selenium.webdriver.common.action_chains import ActionChainsimport timefrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support import uifrom id_and_key import zhanghao,keyfrom selenium.webdriver.chrome.options import Optionschrome_options=Options()#防止被网站识别chrome_options.add_experimental_option('excludeSwitches',['enable-automation'])wait_time=3runtime=300#1.打开浏览器,输入网址browser=webdriver.Chrome(chrome_options=chrome_options)browser.maximize_window()browser.get("https://robo.datayes.com/v2/stock/002475/information#STOCK_POPULAR_FEELINGS")browser.implicitly_wait(10)#加入隐式等待time.sleep(5)# # 寻找立即登录# button = browser.find_element(By.XPATH, '//*[@id="_0d1ab255-c166-4ff8-8005-57b44fc2ea2e"]/div[1]/div[2]/div/p[2]/button')# browser.execute_script("arguments[0].click();", button)# 寻找账号登录在这里button1 = browser.find_element(By.XPATH, '/html/body/div[5]/div/div')browser.execute_script("arguments[0].click();", button1)time.sleep(2)#寻找账号输入框input_id=browser.find_element(By.XPATH,'//*[@id="username"]')input_id.send_keys(zhanghao)#寻找密码输入框input_key=browser.find_element(By.XPATH,'//*[@id="password"]')input_key.send_keys(key)#寻找点击登录button2=browser.find_element(By.XPATH,'//*[@id="dyc-login-register"]/div[2]/div[2]/div[1]/div[3]/div[1]/form/div[3]/div/div/span/button')browser.execute_script("arguments[0].click();", button2)time.sleep(5)#days=eval(input("请调节搜索范围"))#定义步长step=300/daysif step<1:step=1# 鼠标的起始点action = ActionChains(browser)action.move_by_offset(350, 250).perform()while 1:try:action=ActionChains(browser)action.move_by_offset(10,0).perform()except Exception:break#寻找span节点try:wait=ui.WebDriverWait(browser,runtime)wait.until(lambda driver: driver.find_elements(By.XPATH,'//span'))except Exception as error1:print(error1)try:wait.until(lambda driver: driver.find_elements(By.XPATH,'//span'))except Exception as error2:print(error2)time.sleep(2)# time.sleep(1)spans=browser.find_elements(By.XPATH,"//span")print(spans[25].text)# for i in range(len(spans)):# print(i)# print(spans[i].text)# print(len(spans))