项目一 爬取雨课堂视频

目标网站url : https://changjiang.yuketang.cn/v2/web/playback/5183588/slide/2/0
image.png

说明

使用模块

  1. import requests
  2. from bs4 import BeautifulSoup
  3. import re
  4. import asyncio
  5. import aiohttp
  6. import aiofiles
  7. from Crypto.Cipher import AES # pycryptodome
  8. import os

分析

通过抓包工具分析,只要得到m3u8文件,就可以获得每一个ts文件的url,我们通过异步协程的方式下载视频的每一小段,最后合并到一起,便可以得到整个视频.
image.png
image.png

反爬手段

使用加headers,如referer防盗链的处理,给出该网页上级网页url,可以实现应对反爬虫.

  1. headers = {
  2. 'User - Agent': "Mozilla / 5.0(Windows NT 10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 92.0.4515.131 Safari / 537.36 Edg / 92.0.902.73",
  3. 'Referer': 'https: // changjiang.yuketang.cn /'
  4. }
  5. resp = requests.get(url,headers=headers)

代码

若m3u8中采取了数据加密,则需要想要的解密过程.

协程:
一般情况下, 当程序处于 IO操作的时候. 线程都会处于阻塞状态
协程: 当程序遇见了IO操作的时候. 可以选择性的切换到其他任务上.
在微观上是一个任务一个任务的进行切换. 切换条件一般就是IO操作
在宏观上,我们能看到的其实是多个任务一起在执行
多任务异步操作

  1. import requests
  2. from bs4 import BeautifulSoup
  3. import re
  4. import asyncio
  5. import aiohttp
  6. import aiofiles
  7. from Crypto.Cipher import AES # pycryptodome
  8. import os
  9. def download_m3u8_file(url, name):
  10. headers = {
  11. 'User - Agent': "Mozilla / 5.0(Windows NT 10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 92.0.4515.131 Safari / 537.36 Edg / 92.0.902.73",
  12. 'Referer': 'https: // changjiang.yuketang.cn /'
  13. }
  14. resp = requests.get(url,headers=headers)
  15. with open(name, mode="wb") as f:
  16. f.write(resp.content)
  17. async def download_ts(url, name, session):
  18. async with session.get(url) as resp:
  19. async with aiofiles.open(f"test/{name}", mode="wb") as f:
  20. await f.write(await resp.content.read()) # 把下载到的内容写入到文件中
  21. #print(f"{name}下载完毕")
  22. async def aio_download(up_url):
  23. tasks = []
  24. async with aiohttp.ClientSession() as session: # 提前准备好session
  25. async with aiofiles.open("test.m3u8", mode="r", encoding='utf-8') as f:
  26. n=1
  27. async for line in f:
  28. if line.startswith("#"):
  29. continue
  30. # line就是xxxxx.ts
  31. line = line.strip() # 去掉没用的空格和换行
  32. # 拼接真正的ts路径
  33. ts_url = up_url + line
  34. name=str(n)+'.ts'
  35. task = asyncio.create_task(download_ts(ts_url, name, session)) # 创建任务
  36. tasks.append(task)
  37. n=n+1
  38. await asyncio.wait(tasks) # 等待任务结束
  39. def merge_ts():
  40. # mac: cat 1.ts 2.ts 3.ts > xxx.mp4
  41. # windows: copy /b 1.ts+2.ts+3.ts xxx.mp4
  42. print("here3")
  43. lst = []
  44. with open("test.m3u8", mode="r", encoding="utf-8") as f:
  45. n=1
  46. for line in f:
  47. if line.startswith("#"):
  48. continue
  49. name=str(n)+'.ts'
  50. lst.append(f"test\{name}")
  51. n=n+1
  52. s = "+".join(lst) # 1.ts 2.ts 3.ts
  53. print(s)
  54. os.system(f"copy /b {s} test.ts")
  55. print("搞定!")
  56. remove()
  57. def remove():
  58. path = './test'
  59. for i in os.listdir(path):
  60. path_file = os.path.join(path, i)
  61. if os.path.isfile(path_file):
  62. os.remove(path_file)
  63. else:
  64. for f in os.listdir(path_file):
  65. path_file2 = os.path.join(path_file, f)
  66. if os.path.isfile(path_file2):
  67. os.remove(path_file2)
  68. def get_key(url):
  69. headers={
  70. 'user - agent': 'Mozilla / 5.0(Windows NT 10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 92.0.4515.107 Safari / 537.36 Edg / 92.0.902.55',
  71. 'referer': 'https: // www.acwing.com /'
  72. }
  73. resp = requests.get(url,headers=headers)
  74. return resp.text
  75. async def dec_ts(name, key):
  76. aes = AES.new(key=key, IV=b"0000000000000000", mode=AES.MODE_CBC)
  77. async with aiofiles.open(f"test/{name}", mode="rb") as f1,\
  78. aiofiles.open(f"test/temp_{name}", mode="wb") as f2:
  79. bs = await f1.read() # 从源文件读取内容
  80. await f2.write(aes.decrypt(bs)) # 把解密好的内容写入文件
  81. print(f"{name}处理完毕")
  82. async def aio_dec(key):
  83. # 解密
  84. tasks = []
  85. async with aiofiles.open("test.m3u8", mode="r", encoding="utf-8") as f:
  86. n=1
  87. async for line in f:
  88. if line.startswith("#"):
  89. continue
  90. line = line.strip()
  91. # 开始创建异步任务
  92. name=str(n)+'.ts'
  93. task = asyncio.create_task(dec_ts(name, key))
  94. tasks.append(task)
  95. n=n+1
  96. await asyncio.wait(tasks)
  97. if __name__=='__main__':
  98. m3u8url="https://tx-xuetangx.video.yximgs.com/gifshow-xuetangx/184eb9fd3701925921229800624/playlist_eof.m3u8?sign=1629121310-5579969482634986343-0-a13f16a96d8f3577260282b552795a7e"
  99. up='https://tx-xuetangx.video.yximgs.com/gifshow-xuetangx/184eb9fd3701925921229800624/'
  100. download_m3u8_file(m3u8url,"test.m3u8")
  101. asyncio.run(aio_download(up))
  102. merge_ts()

数据说明

获取m3u8文件

image.png

获取每一个ts文件

image.png

合并为整段视频

image.png

项目二 使用scrapy爬取图片

说明

源页面

http://sc.chinaz.com/tupian/
image.png

反爬手段

image.png

模块

  1. import scrapy
  2. from imgsPro.items import ImgsproItem

分析

  • 图片数据爬取之ImagesPipeline
    - 基于scrapy爬取字符串类型的数据和爬取图片类型的数据区别?
    - 字符串:只需要基于xpath进行解析且提交管道进行持久化存储
    - 图片:xpath解析出图片src的属性值。单独的对图片地址发起请求获取图片二进制类型的数据

    • ImagesPipeline:
      - 只需要将img的src的属性值进行解析,提交到管道,管道就会对图片的src进行请求发送获取图片的二进制类型的数据,且还会帮我们进行持久化存储。
      - 需求:爬取站长素材中的高清图片
      - 使用流程:
      - 数据解析(图片的地址)
      - 将存储图片地址的item提交到制定的管道类
      - 在管道文件中自定制一个基于ImagesPipeLine的一个管道类
      - get_media_request
      - file_path
      - item_completed
      - 在配置文件中:
      - 指定图片存储的目录:IMAGES_STORE = ‘./imgs_bobo’
      - 指定开启的管道:自定制的管道类

      数据

      image.png

      项目3 爬取小说

      说明

      url: http://dushu.baidu.com/api/pc/getCatalog?data={“book_id”:”4315647161”}

      分析

      通过目录获取各个章节的url,通过异步协程的方式分别爬取每个章节,通过xpath解析出正文内容,保存到txt中。

      数据

      image.png
      image.png