使用C#和HtmlAgilityPack打造强大的Snapchat视频爬虫

概述
Snapchat作为一款备受欢迎的社交媒体应用,允许用户分享照片和视频。然而,由于其特有的内容自动消失特性,爬虫开发面临一些挑战。本文将详细介绍如何巧妙运用C#和HtmlAgilityPack库,构建一个高效的Snapchat视频爬虫。该爬虫能够从Snapchat网页版中提取视频链接,并将其下载保存到本地。为了提升爬虫的效率和可靠性,我们将使用代理IP技术和多线程技术,以规避Snapchat的反爬机制。
细节
C#和HtmlAgilityPack库
C#作为一门功能强大、易用的面向对象编程语言,适用于各类应用程序的开发。C#可以在.NET Framework或.NET Core上运行,这两者提供了丰富的类库和工具,方便开发者进行应用开发。
HtmlAgilityPack是一款专为.NET平台设计的HTML解析库,支持XPath和LINQ查询,能够轻松从HTML文档中提取数据。其强大之处在于能够处理不规范的HTML结构,同时支持对HTML文档结构和内容进行修改。HtmlAgilityPack是一个开源项目,源码和文档可在其官方网站查阅。
为使用HtmlAgilityPack库,我们需在Visual Studio中创建一个控制台应用项目,通过NuGet包管理器安装HtmlAgilityPack库。NuGet是.NET平台的包管理工具,可便捷管理项目依赖关系。
代理IP技术
代理IP技术是一种隐藏真实IP地址的方法,通过中间服务器访问目标网站,既可保护隐私安全,又能绕过地域限制和反爬机制,提高爬虫的成功率和效率。爬虫代理是一个专业服务平台,提供高质量的代理IP资源,支持多种协议和认证方式,适用于各种爬虫场景。
在C#中,使用HttpClient对象发送请求,可通过设置Proxy属性指定代理服务器的地址和认证信息,以实现代理IP的应用。
多线程技术
多线程技术是提高程序性能的有效手段,可同时执行多个任务,最大程度利用CPU资源,提高响应速度和吞吐量。对于爬虫而言,多线程技术有助于实现并发爬取,提高效率和覆盖范围。
在C#中,可通过创建Task对象,使用Task.Run方法启动新线程执行指定方法,并结合SemaphoreSlim对象限制并发线程数,保证程序稳定性。
Snapchat视频爬虫的实现
Snapchat网页版的地址是https://story.snapchat.com/,通过分析网页结构和请求,我们可以发现Snapchat网页是一个单页应用,使用React框架进行渲染。数据通过Ajax请求获取,其中包括一个token参数用于身份验证。在C#中,我们通过HttpClient对象发送请求,提取并保存token值。
主要请求为https://story.snapchat.com/api/v1/stories,获取故事列表。每个故事有id和title,可根据这些信息筛选感兴趣的故事。为获取故事的视频,需发送https://story.snapchat.com/api/v1/story/{story_id}请求,其中{story_id}是故事id。使用HttpClient对象发送这些请求,HtmlAgilityPack解析返回的JSON数据,提取视频链接,再用HttpClient对象下载并保存视频到本地。
为提升效率,采用多线程技术,为每个故事创建一个线程同时获取和下载视频。通过SemaphoreSlim对象控制线程数量,以避免Snapchat的反爬机制。
以下是完整代码,包含中文注释,可在Visual Studio中运行测试:
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using HtmlAgilityPack;namespace SnapchatVideoCrawler
{class Program{// 定义HttpClient对象,用于发送和接收HTTP请求和响应static HttpClient httpClient = new HttpClient();// 定义HtmlDocument对象,用于解析HTML文档static HtmlDocument htmlDocument = new HtmlDocument();// 定义SemaphoreSlim对象,用于控制并发线程数static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(10);// 定义Snapchat网页版的网址static string snapchatUrl = "https://story.snapchat.com/";// 定义Snapchat的token值,用于验证身份,需要从浏览器的本地存储中获取static string snapchatToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzbmFwY2hhdCIsInN1YiI6ImFub255bW91cyIsImF1ZCI6InN0b3J5LnNuYXBjaGF0LmNvbSIsImlhdCI6MTYxNjQ4MjE3NCwiZXhwIjoxNjE2NTY4NTc0LCJqdGkiOiI1ZjYyYzQ4Zi1kYjQyLTQ3ZjUtYjEzZC0wZjQwZjEzZjIwYjgifQ.0t7gqf7Z8p0VZyXQy0sXnOa7l0o0Z8fZ6Z0T0f0f0f0";// 定义亿牛云爬虫代理的域名、端口、用户名和密码,需要从官网获取static string proxyHost = "http://www.16yun.cn";static int proxyPort = 9010;static string proxyUser = "16YUN";static string proxyPass = "16IP";// 定义视频保存的文件夹路径static string videoFolder = @"C:\SnapchatVideos\";static async Task Main(string[] args){// 创建视频保存的文件夹,如果不存在Directory.CreateDirectory(videoFolder);// 设置HttpClient对象的默认请求头,添加token值httpClient.DefaultRequestHeaders.Add("token", snapchatToken);// 获取Snapchat的故事列表var stories = await GetStoriesAsync();// 遍历每个故事foreach (var story in stories){// 获取故事的id和titlevar storyId = story.Id;var storyTitle = story.Title;// 打印故事的信息Console.WriteLine($"Story: {storyTitle} ({storyId})");// 创建并启动一个新的线程,执行GetAndDownloadVideos方法,传入故事的id和titleTask.Run(() => GetAndDownloadVideos(storyId, storyTitle));}// 等待所有线程完成await semaphoreSlim.WaitAsync();semaphoreSlim.Release();// 打印完成信息Console.WriteLine("All videos downloaded!");}// 定义一个异步方法,用于获取Snapchat的故事列表static async Task<HtmlNodeCollection> GetStoriesAsync(){// 定义Snapchat的故事列表的请求地址string storiesUrl = snapchatUrl + "api/v1/stories";// 发送GET请求,获取故事列表的JSON数据var storiesJson = await httpClient.GetStringAsync(storiesUrl);// 使用HtmlDocument对象解析JSON数据,返回一个HtmlNode对象var storiesNode = htmlDocument.Parse(storiesJson);// 使用XPath查询,从HtmlNode对象中提取故事列表,返回一个HtmlNodeCollection对象var stories = storiesNode.SelectNodes("//stories/story");// 返回故事列表return stories;}// 定义一个异步方法,用于获取并下载一个故事的视频static async Task GetAndDownloadVideos(string storyId, string storyTitle){// 使用SemaphoreSlim对象的WaitAsync方法,尝试进入该区域,如果成功则返回一个Task对象,否则等待直到有空位await semaphoreSlim.WaitAsync();try{// 定义一个故事的详细信息的请求地址,使用故事的id替换占位符string storyUrl = snapchatUrl + $"api/v1/story/{storyId}";// 创建一个新的HttpClient对象,用于发送该请求var storyClient = new HttpClient();// 设置HttpClient对象的默认请求头,添加token值storyClient.DefaultRequestHeaders.Add("token", snapchatToken);// 创建一个新的WebProxy对象,用于设置代理服务器的地址和认证信息,使用亿牛云爬虫代理的域名、端口、用户名和密码var proxy = new WebProxy(proxyHost, proxyPort);proxy.Credentials = new NetworkCredential(proxyUser, proxyPass);// 设置HttpClient对象的Proxy属性,指定代理服务器storyClient.Proxy = proxy;// 发送GET请求,获取故事的详细信息的JSON数据var storyJson = await storyClient.GetStringAsync(storyUrl);// 使用HtmlDocument对象解析JSON数据,返回一个HtmlNode对象var storyNode = htmlDocument.Parse(storyJson);// 使用XPath查询,从HtmlNode对象中提取视频列表,返回一个HtmlNodeCollection对象var videos = storyNode.SelectNodes("//story/snaps/snap/media/video");// 遍历每个视频foreach (var video in videos){// 获取视频的链接var videoUrl = video.GetAttributeValue("url", "");// 打印视频的链接Console.WriteLine($"Video: {videoUrl}");// 下载并保存视频到本地,使用故事的title和视频的url作为文件名await DownloadVideoAsync(videoUrl, videoFolder + storyTitle + "_" + videoUrl.Split('/').Last());}}catch (Exception ex){// 如果发生异常,打印异常信息Console.WriteLine($"Error: {ex.Message}");}finally{// 使用SemaphoreSlim对象的Release方法,离开该区域,释放一个空位semaphoreSlim.Release();}}// 定义一个异步方法,用于下载并保存一个视频static async Task DownloadVideoAsync(string videoUrl, string videoPath){// 创建一个新的HttpClient对象,用于发送该请求var videoClient = new HttpClient();// 设置HttpClient对象的默认请求头,添加token值videoClient.DefaultRequestHeaders.Add("token", snapchatToken);// 创建一个新的WebProxy对象,用于设置代理服务器的地址和认证信息,使用亿牛云爬虫代理的域名、端口、用户名和密码var proxy = new WebProxy(proxyHost, proxyPort);proxy.Credentials = new NetworkCredential(proxyUser, proxyPass);// 设置HttpClient对象的Proxy属性,指定代理服务器videoClient.Proxy = proxy;// 发送GET请求,获取视频的字节数据var videoBytes = await videoClient.GetByteArrayAsync(videoUrl);// 使用File类的WriteAllBytes方法,将视频的字节数据写入到指定的文件路径File.WriteAllBytes(videoPath, videoBytes);}}
}
结束语
通过本文,我们深入探讨了如何使用C#和HtmlAgilityPack库构建一个高效的Snapchat视频爬虫。代理IP技术和多线程技术的巧妙应用使得爬虫更具稳定性和高效性。希望这篇文章对你理解爬虫技术和应用有所帮助,欢迎在实际项目中应用并根据需要进行定制。祝愿你的爬虫项目取得圆满成功!
相关文章:
使用C#和HtmlAgilityPack打造强大的Snapchat视频爬虫
概述 Snapchat作为一款备受欢迎的社交媒体应用,允许用户分享照片和视频。然而,由于其特有的内容自动消失特性,爬虫开发面临一些挑战。本文将详细介绍如何巧妙运用C#和HtmlAgilityPack库,构建一个高效的Snapchat视频爬虫。该爬虫能…...
c/c++的字符和字符串输入输出
注: 1.下面这些为本人大学四年所用过的处理办法, 至今为止遇到的所有编程题都能够使用。如果需要了解更多关于putchar,cin.get,cin.getline等的请自行搜索。 2.getchar相当于获取一个字符,可以实现单个字符的输入以及通过循环实现多个字符输…...
学习设计模式的网站
Refactoring and Design Patternshttps://refactoring.guru/...
Hadoop学习笔记(HDP)-Part.08 部署Ambari集群
目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …...
IDEA加载阿里Java规范插件
IDEA加载阿里巴巴Java开发手册插件,在写代码的时候会自动扫描代码规范。 1、打开Settings 2、打开Plugins 3、搜索Alibaba Java Code Guidelines(XenoAmess TPM)插件,点击Install进行安装,然后重启IDE生效。 4、鼠标右…...
【CSP】202305-1_重复局面Python实现
文章目录 [toc]试题编号试题名称时间限制内存限制题目背景问题描述输入格式输出格式样例输入样例输出样例说明子任务提示Python实现 试题编号 202305-1 试题名称 重复局面 时间限制 1.0s 内存限制 512.0MB 题目背景 国际象棋在对局时,同一局面连续或间断出现3次或3…...
html5各行各业官网模板源码下载(1)
文章目录 1.来源2.源码模板2.1 HTML5白色简洁设计师网站模板2.2 HTML5保护野生动物响应式网站模板 作者:xcLeigh 文章地址:https://blog.csdn.net/weixin_43151418/article/details/134682321 html5各行各业官网模板源码下载,这个主题覆盖各行…...
6 Redis缓存设计与性能优化
缓存穿透 缓存穿透是指查询一个根本不存在的数据, 缓存层和存储层都不会命中, 通常出于容错的考虑, 如果从存储层查不到数据则不写入缓存层。缓存穿透将导致不存在的数据每次请求都要到存储层去查询, 失去了缓存保护后端存储的意义…...
SpringCloud常见问题
1、什么是Spring Cloud? Spring Cloud是一款基于Spring Boot框架开发的微服务框架,它为开发人员提供了一系列的组件和工具,可以帮助开发人员快速构建和部署微服务,提高开发效率和项目可维护性。Spring Cloud提供了包括服务注册与…...
实战演练 | 在 Navicat 中格式化日期和时间
Navicat 支持团队收到来自用户常问的一个问题是,如何将网格和表单视图中的日期和时间进行格式化。其实这个很简单。今天,我们将介绍在 Navicat Premium 中进行全局修改日期和时间格式的步骤。 如果你想边学边用,欢迎点击 这里 下载免费全功能…...
mysql面试题分享带答案
数据库索引的原理,为什么要用B树,为什么不用二叉树? 可以从几个维度去看这个问题,查询是否够快,效率是否稳定,存储数据多少,以及查找磁盘次数,为什么不是二叉树,为什么不…...
利用 Python进行数据分析实验(一)
一、实验目的 使用Python解决简单问题 二、实验要求 自主编写并运行代码,按照模板要求撰写实验报告 三、实验步骤 本次实验共有5题: 有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少&…...
Jupyter Notebook工具
Jupyter Notebook 是一个交互式的笔记本环境,允许用户以网页形式编写和分享代码、文本、图像以及其它多媒体内容。它支持超过 40 种编程语言,最常用的是 Python。 以下是 Jupyter Notebook 工具的一些特点和用法: 1. 特点: 交互式…...
c语言上机小练(有点难)
1.题目 用指向数组的指针编程实现:输入一个字符串,内有数字和非数字符号,如:a123x456(此处一个空格)17960?302tab5876。将其中连续的数字作为一个十进制整数,依次存放到一个数组a中。例如&…...
<JavaEE> 什么是线程安全?产生线程不安全的原因和处理方式
目录 一、线程安全的概念 二、线程不安全经典示例 三、线程不安全的原因和处理方式 3.1 线程的随机调度和抢占式执行 3.2 修改共享数据 3.3 关键代码或指令不是“原子”的 3.4 内存可见性和指令重排序 四、Java标准库自带的线程安全类 一、线程安全的概念 线程安全是指…...
Kotlin 中的 also 和 run:选择正确的作用域函数
在 Kotlin 中,also 和 run 是两个十分有用的作用域函数。 虽然它们在功能上相似,但各自有独特的用途和适用场景。 一、分析: also:在对象的上下文中执行给定的代码块,并返回对象本身。它的参数是一个接收对象并返回…...
ZKP Understanding Nova (1): MinRoot Example
Understanding Nova Kothapalli, Abhiram, Srinath Setty, and Ioanna Tzialla. “Nova: Recursive zero-knowledge arguments from folding schemes.” Annual International Cryptology Conference. Cham: Springer Nature Switzerland, 2022. Nova: Paper Code 1. Unders…...
0基础学java-day14
一、集合 前面我们保存多个数据使用的是数组,那么数组有不足的地方,我们分析一下 1.数组 2 集合 数据类型也可以不一样 3.集合的框架体系 Java 的集合类很多,主要分为两大类,如图 :[背下来] package com.hspedu.c…...
创建conan包-工具链
创建conan包-工具链 1 Toolchains 本文是基于对conan官方文档Toolchains翻译而来, 更详细的信息可以去查阅conan官方文档。 1 Toolchains Toolchains are the new way to integrate with build systems in Conan. Recipes can define a generate() method that wi…...
IntelliJ IDE 插件开发 | (二)UI 界面与数据持久化
系列文章 IntelliJ IDE 插件开发 |(一)快速入门 前言 在上一篇文章中介绍了在IDEA下开发、运行和安装插件的基本步骤,因此创建项目等基础步骤不再赘述,本文则开始介绍如何进行 UI 界面的开发以及相关数据的持久化存储ÿ…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
