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

亿牛云代理.png

概述

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和title
                var storyId = story.Id;
                var storyTitle = story.Title;

                // 打印故事的信息
                Console.WriteLine($"Story: {storyTitle} ({storyId})");

                // 创建并启动一个新的线程,执行GetAndDownloadVideos方法,传入故事的id和title
                Task.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技术和多线程技术的巧妙应用使得爬虫更具稳定性和高效性。希望这篇文章对你理解爬虫技术和应用有所帮助,欢迎在实际项目中应用并根据需要进行定制。祝愿你的爬虫项目取得圆满成功!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/194031.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Nginx Openresty通过Lua+Redis 实现动态封禁IP

需求 为了封禁某些爬虫或者恶意用户对服务器的请求&#xff0c;我们需要建立一个动态的 IP 黑名单。对于黑名单中的 IP &#xff0c;我们将拒绝提供服务。并且可以设置封禁失效时间 环境准备 linux version: centos7 / ubuntu 等 redis version: 5.0.5 nginx version: nginx…

高端影像仪:打破微小产品测量局限

在现代工业生产中&#xff0c;影像仪以CCD数位影像为基石&#xff0c;将计算机屏幕测量技术与空间几何运算的能力融为一体&#xff0c;可以用于测量微小产品的各种尺寸和形状&#xff0c;为生产过程中的质量控制提供重要的参考依据。 影像仪产品内置高精度光学电动双倍镜头&am…

竞赛选题 题目:基于大数据的用户画像分析系统 数据分析 开题

文章目录 1 前言2 用户画像分析概述2.1 用户画像构建的相关技术2.2 标签体系2.3 标签优先级 3 实站 - 百货商场用户画像描述与价值分析3.1 数据格式3.2 数据预处理3.3 会员年龄构成3.4 订单占比 消费画像3.5 季度偏好画像3.6 会员用户画像与特征3.6.1 构建会员用户业务特征标签…

百度人工智能培训第一天笔记

参加了百度人工智能初步培训&#xff0c;主要是了解一下现在人工智能的基本情况&#xff0c;以便后续看可以参与一些啥&#xff1f; 下面就有关培训做一些记录&#xff0c;以便后续可以继续学习。 一、理论基础部分 二、实际操作部分 主要学习的百度人工智能平台如下&#xf…

Go——三、运算符以及流程控制

Go 一、Go语言运算符1、算数运算符2、关系运算符3、逻辑运算符4、位运算符5、赋值运算符6、其他运算符7、运算符优先级 二、Go的流程控制1、if else2、for 循环结构3、for range&#xff08;键值循环&#xff09;4、switch case5、break&#xff1a;跳出循环6、go&#xff1a;跳…

IDEA编译器技巧-提示词忽略大小写

IDEA编译器技巧-提示词忽略大小写 写代码时,每次创建对象都要按住 Shift 字母 做大写开头, 废手, 下面通过编译器配置解放Shift 键 setting -> Editor -> General -> Code Completion -> Match case 把这个√去掉, 创建对象就不需要再按住 Shift 键 示例: 1.…

Android Termux SFTP如何实现远程文件传输

文章目录 1. 安装openSSH2. 安装cpolar3. 远程SFTP连接配置4. 远程SFTP访问4. 配置固定远程连接地址 SFTP&#xff08;SSH File Transfer Protocol&#xff09;是一种基于SSH&#xff08;Secure Shell&#xff09;安全协议的文件传输协议。与FTP协议相比&#xff0c;SFTP使用了…

Linux静态库,共享库,计算机基础知识

1.库文件: 1).库文件库是一组预先编译好的方法的集合;Linux系统存储库的位置一般在/lib 和 /usr/lib (64位系统/usr/lib64)库的头文件放在/usr/include 2).库的分类 静态库:libxxx.a(命名规则) 共享库:libxxx.so(命名规则) 3).准备文件: //add.c int add(int x,int y) { retu…

设计模式—迪米特原则(LOD)

1.背景 1987年秋天由美国Northeastern University的Ian Holland提出&#xff0c;被UML的创始者之一Booch等普及。后来&#xff0c;因为在经典著作《 The Pragmatic Programmer》而广为人知。 2.概念 迪米特法则&#xff08;Law of Demeter&#xff09;又叫作最少知识原则&…

免费部署开源大模型

参考&#xff1a;【大模型-第一篇】在阿里云上部署ChatGLM3-CSDN博客 ChatGLM 是一个开源的、支持中英双语的对话语言模型&#xff0c;由智谱 AI 和清华大学 KEG 实验室联合发布&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;具有 62 亿参数。ChatGLM3-6B 更…

Fluent热辐射壁面设置

对于固体壁面&#xff0c;可分为&#xff1a; 内部面外部面 外部面&#xff0c;若需要考虑外部热辐射的影响&#xff0c;需要将类型改为“mixed”或者“radiation”类型&#xff0c;并设置外部的发射率。 内部面通常为“wall”和“wall-shadow”的配对形式。 对于两侧均是透明…

了解FastSam:一个通用分割模型(草记)

想尝试这个FastSam的部署&#xff0c;但至今还没跑通&#xff0c;一个问题能带出一片问题&#xff0c;感觉挺心情挺郁闷的。后来和学长交流的时候&#xff0c;说那就是学少了&#xff0c;没必要急着将跑通它作为目的。也很有道理&#xff0c;这个任务还不太适合我当前的水平&am…

vscode Markdown 预览样式美化多方案推荐

优雅的使用 vscode写 Markdown&#xff0c;预览样式美化 1 介绍 我已经习惯使用 vscode 写 markdown。不是很喜欢他的 markdown 样式&#xff0c;尤其是代码块高亮的样式。当然用 vscode 大家基本上都会选择安装一个Markdown-preview-enhanced的插件&#xff0c;这个插件的确…

java分布式锁分布式锁

java分布式&锁&分布式锁 锁 锁的作用&#xff1a;有限资源的情况下&#xff0c;控制同一时间段&#xff0c;只有某些线程&#xff08;用户/服务器&#xff09;能访问到资源。 锁在java中的实现&#xff1a; synchronized关键字并发包的类 缺点&#xff1a;只对单个的…

HCIA-H12-811题目解析(2)

1、【单选题】 在以太网这种多点访问网络上PPPOE服务器可以通过一个以太网端口与很多PPPOE客户端建立起PPP连接&#xff0c;因此服务器必须为每个PPP会话建立唯一的会话标识符以区分不同的连接PPPOE会使用什么参数建立会话标识符? 2、【单选题】PPP协议定义的是OSI参考模型中…

Chem. Eng. J | 掌控基于ESIPT的AIE效应设计具有单组分白光发射的光学材料

今天为大家介绍一篇近期发表在Chemical Engineering Journal上的论文&#xff1a;Controlling ESIPT-based AIE effects for designing optical materials with single-component white-light emission。论文通讯作者为中南大学董界副教授和曾文彬教授&#xff0c;论文第一作者…

【Leetcode】907. 子数组的最小值之和

给定一个整数数组 arr&#xff0c;找到 min(b) 的总和&#xff0c;其中 b 的范围为 arr 的每个&#xff08;连续&#xff09;子数组。 由于答案可能很大&#xff0c;因此 返回答案模 10^9 7 。 示例 1&#xff1a; 输入&#xff1a;arr [3,1,2,4] 输出&#xff1a;17 解释&…

1、Linux_介绍和安装

1. Linux概述 Linux&#xff1a;是基于Unix的一个开源、免费的操作系统&#xff0c;其稳定性、安全性、处理多并发能力强&#xff0c;目前大多数企业级应用甚至是集群项目都部署运行在linux操作系统之上&#xff0c;在我国软件公司得到广泛的使用 Unix&#xff1a;是一个强大…

RK3568平台开发系列讲解(Linux系统篇)pinctrl api介绍及实验

&#x1f680;返回专栏总目录 文章目录 一、pinctrl函数介绍二、设备树案例三、驱动案例 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01;&#x1f604; &#x1f4e2;本篇将介绍pinctrl api及其使用案例 。 一、pinctrl函数介绍 ①获取设备对应的 pinctrl…

TS 函数及多态

TS 能推导出函数体中的类型&#xff0c;但多数情况下无法推导出参数的类型&#xff0c;只有少数特殊情况下能根据上下文推导参数的类型。返回类型能推导出&#xff0c;不过也可以显式注解。 1 声明和调用函数 一般来说&#xff0c;在方法中的this值为调用该方法时位于点号左侧…