【梨视频下载案例】
【一】前提:代理池搭建
【1】引入
- 代理池是一种用于获取可用代理服务器的工具,可以帮助用户在发送请求时隐藏真实IP地址并提高访问稳定性。
- 开源的代理池核心原理:https://github.com/jhao104/proxy_pool
- 1 使用爬虫技术,爬取网上免费的代理
- 2 爬完回来做验证,如果能用,存到redis中
- 启动调度程序,爬代理,验证,存到redis中
- python proxyPool.py schedule
步骤1:选择合适的开源软件
- 首先,我们需要选择一款适合搭建代理池的开源软件。
- 目前市面上有很多可供选择的软件,比如Scrapy、ProxyPool等。
- 根据自己的需求和技术能力,选择一款稳定可靠的软件进行搭建。
步骤2:安装依赖和配置环境
- 根据所选软件的官方文档,安装相关依赖并配置环境。
- 通常情况下,您需要安装Python以及相应的库和模块。
步骤3:编写代理池程序
根据软件的要求,编写代理池程序。程序主要包括以下几个部分:
- 代理获取:从免费代理网站或付费代理提供商获取代理IP,并进行有效性验证。
- 代理存储:将有效的代理IP存储在数据库或其他存储介质中,以供后续使用。
- 代理检测与维护:定时检测已存储的代理IP的有效性,并根据需要进行维护,如删除无效的代理IP。
步骤4:运行代理池程序
- 确认程序编写完成后,通过命令行或脚本运行代理池程序。
- 程序会自动获取、存储和维护代理IP。
步骤5:从代理池中随机取出代理发起请求
- 在需要使用代理的场景下,可以从代理池中随机选择一个可用的代理IP,并将其添加到请求头中。
- 示例代码如下:
import random
import requests
def get_random_proxy():
# 从数据库或其他存储介质中获取代理池中的代理IP列表
proxy_list = ['ip1:port1', 'ip2:port2', 'ip3:port3', ...]
# 随机选择一个代理IP
random_proxy = random.choice(proxy_list)
return random_proxy
def send_request(url):
# 获取随机代理IP
proxy = get_random_proxy()
# 设置代理参数
proxies = {
'http': 'http://' + proxy,
'https': 'https://' + proxy
}
try:
# 发起请求
response = requests.get(url, proxies=proxies, timeout=10)
# 处理响应数据
# ...
except Exception as e:
# 请求异常处理
# ...
# 示例调用
url = "http://example.com"
send_request(url)
- 通过以上步骤,您就可以搭建一个代理池,并从中随机选择代理IP发送请求。
- 记得定期更新和维护代理池,以确保代理IP的有效性和可用性。
【2】拉取第三方镜像
- pycharm
- Git
- Clone
- Git from version control
https://github.com/jhao104/proxy_pool
【3】搭建虚拟环境
mkvirtualenv -p python39 proxypool
【4】安装依赖
pip install -r requirements.txt
【5】更新配置
# setting.py 为项目配置文件
# 配置API服务
HOST = "0.0.0.0" # IP
PORT = 5000 # 监听端口
# 配置数据库
# Redis数据库
DB_CONN = 'redis://127.0.0.1:8888/2'
# 配置 ProxyFetcher
PROXY_FETCHER = [
"freeProxy01", # 这里是启用的代理抓取方法名,所有fetch方法位于fetcher/proxyFetcher.py
"freeProxy02",
# ....
]
# 代理验证目标网站
HTTP_URL = "http://httpbin.org"
HTTPS_URL = "https://www.qq.com"
【6】启动项目
- 如果已经具备运行条件, 可用通过proxyPool.py启动。
- 程序分为: schedule 调度程序 和 server Api服务
(1)启动调度程序
- 启动调度程序,爬代理,验证,存到redis中
python proxyPool.py schedule
(2)启动webApi服务
- 使用flask启动服务,对外开放了几个接口,向某个接口发请求,就能随机获取一个代理
python proxyPool.py server
【7】使用
(1)Api
- 启动web服务后, 默认配置下会开启 http://127.0.0.1:5010 的api接口服务:
api | method | Description | params |
---|---|---|---|
/ | GET | api介绍 | None |
/get | GET | 随机获取一个代理 | 可选参数: ?type=https 过滤支持https的代理 |
/pop | GET | 获取并删除一个代理 | 可选参数: ?type=https 过滤支持https的代理 |
/all | GET | 获取所有代理 | 可选参数: ?type=https 过滤支持https的代理 |
/count | GET | 查看代理数量 | None |
/delete | GET | 删除代理 | ?proxy=host:ip |
【二】主代码
# -*-coding: Utf-8 -*-
# @File : 03练习爬取视频网站 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/8/18
import multiprocessing
import os
import re
import threading
import time
from concurrent.futures import ThreadPoolExecutor, wait
from fake_useragent import UserAgent
import requests
class Crawl_Li_Video():
def __init__(self, n):
self.headers = {
"User-Agent": UserAgent().random,
}
self.proxy = self.test_proxy()
self.page = n
def get_proxy(self):
return requests.get("http://127.0.0.1:5010/get/").json()
def delete_proxy(self, proxy):
requests.get("http://127.0.0.1:5010/delete/?proxy={}".format(proxy))
def test_proxy(self):
retry_count = 5
proxy_get = self.get_proxy().get("proxy")
proxy = {
"http": proxy_get,
}
try:
response = requests.get('https://www.baidu.com/', proxies=proxy)
if response.status_code == 200:
print("温馨提示::>> 代理测试完成!可以使用!")
return proxy
else:
self.delete_proxy(proxy_get)
print("温馨提示::>> 代理测试失败!正在重启!")
self.test_proxy()
except Exception as e:
self.delete_proxy(proxy_get)
print('程序错误:>>>', e)
def get_now_urls(self):
# 24
tag_url_list = []
for i in range(self.page):
tag_url = f'https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=1&start={24 * i}'
tag_url_list.append(tag_url)
# https://www.pearvideo.com/video_1007601
result_urls_dict = {}
count = 0
for tag_url in tag_url_list:
count += 1
try:
response = requests.get(url=tag_url, headers=self.headers, proxies=self.proxy)
except Exception as e:
self.proxy = self.test_proxy()
print(e)
continue
response.encoding = 'utf8'
page_text = response.text
re_url = r'<a href="(.*?)" class="vervideo-lilink actplay">'
re_title = r'<div class="vervideo-title">(.*?)</div>'
re_url = re.compile(re_url)
re_title = re.compile(re_title)
# print(page_text)
detail_url_list = re.findall(re_url, page_text)
detail_url_title = re.findall(re_title, page_text)
pairs = zip(detail_url_list, detail_url_title)
result_dict = {key: value for key, value in pairs}
result_urls_dict[(count)] = result_dict
return self.get_download_url_list(result_urls_dict)
def get_download_url_list(self, result_urls_dict):
download_urls_dict = {}
for i in range(1, len(result_urls_dict) + 1):
detail_dict = {}
for video_id, title in result_urls_dict.get(i).items():
# video_1467342
now_page_url = 'https://www.pearvideo.com/' + video_id
self.headers['Referer'] = now_page_url
now_page_url = f'https://www.pearvideo.com/videoStatus.jsp?contId={video_id.split("_")[-1]}'
try:
response = requests.get(url=now_page_url, headers=self.headers, proxies=self.proxy)
except Exception as e:
self.proxy = self.test_proxy()
print('请求下载链接出错:>>>', e)
continue
# 当前视频地址
# https://www.pearvideo.com/video_1463575
# 返回视频地址
# https://www.pearvideo.com/videoStatus.jsp?contId=1463575&mrd=0.5277998673469977
# 返回假视频地址
# "https://video.pearvideo.com/mp4/adshort/20181026/ 1692351221819 -13126761 _adpkg-ad_hd.mp4"
# 返回真视频地址
# https://video.pearvideo.com/mp4/adshort/20181026/ cont-1463575 -13126761 _adpkg-ad_hd.mp4
response.encoding = 'utf8'
data_dict = response.json()
fake_url = data_dict['videoInfo']['videos']['srcUrl']
rale_url = fake_url.replace(fake_url.split('/')[-1].split('-')[0], f'cont-{video_id.split("_")[-1]}')
detail_dict[title] = rale_url
download_urls_dict[i] = detail_dict
return download_urls_dict
def download_mp4(self, page_number, download_url_dict):
for video_title, video_url in download_url_dict.items():
try:
response = requests.get(url=video_url, headers=self.headers, proxies=self.proxy)
except Exception as e:
self.proxy = self.test_proxy()
print(f'请求视频 {video_url} <---> {video_title} 数据出错:>>>')
print(f'错误原因:>>> {e}')
print('---------------')
continue
file_name = os.path.join(os.path.dirname(__file__), f'第{page_number}页视频')
if not os.path.exists(file_name):
os.mkdir(file_name)
file_path = os.path.join(file_name, video_title + '.mp4')
try:
with open(file_path, 'wb') as fp:
for line in response.iter_content():
fp.write(line)
print(f'当前第 {page_number} 页视频 {video_title} 下载完成 !')
except Exception as e:
print('下载发生错误:>>>', e)
continue
def main_ThreadPoolExecutor(self):
download_urls_dict = self.get_now_urls()
pool = ThreadPoolExecutor(max_workers=5)
task_list = []
for page_number, download_url_dict in download_urls_dict.items():
task = pool.submit(self.download_mp4, page_number, download_url_dict)
task_list.append(task)
wait(task_list)
pool.shutdown() # 阻塞等待
def main_Thread(self):
download_urls_dict = self.get_now_urls()
task_list = []
for page_number, download_url_dict in download_urls_dict.items():
task = threading.Thread(target=self.download_mp4, args=(page_number, download_url_dict))
task.start()
task_list.append(task)
for task in task_list:
task.join()
def main_multiprocessing(self):
download_urls_dict = self.get_now_urls()
task_list = []
for page_number, download_url_dict in download_urls_dict.items():
task = multiprocessing.Process(target=self.download_mp4, args=(page_number, download_url_dict))
task.start()
task_list.append(task)
for task in task_list:
task.join()
if __name__ == '__main__':
start = time.time()
crawl = Crawl_Li_Video(10)
# crawl.main_ThreadPoolExecutor()
# crawl.main_Thread()
crawl.main_multiprocessing()
print(f'总耗时:>>{time.time() - start} s')
本文来自博客园,作者:Chimengmeng,转载请注明原文链接:https://www.cnblogs.com/dream-ze/p/17647620.html