国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

c# 通過webView2模擬登陸小紅書網(wǎng)頁版,解析無水印視頻圖片,以及解決X-s,X-t簽名驗證【2023年4月29日】

這篇具有很好參考價值的文章主要介紹了c# 通過webView2模擬登陸小紅書網(wǎng)頁版,解析無水印視頻圖片,以及解決X-s,X-t簽名驗證【2023年4月29日】。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、c# WebView2簡介
? 1.一開始使用WebBrowser,因為WebBrowser控件使用的是ie內(nèi)核,經(jīng)過修改注冊表切換為Edge內(nèi)核后,
發(fā)現(xiàn)Edge內(nèi)核版本較低,加載一些視頻網(wǎng)站提示“瀏覽器版本過低“,”視頻無法加載“。
c# 通過webView2模擬登陸小紅書網(wǎng)頁版,解析無水印視頻圖片,以及解決X-s,X-t簽名驗證【2023年4月29日】

2.WebBrowser內(nèi)核版本與WebView2比較

WebBrowser內(nèi)核版本:
內(nèi)核版本 (Version) Edge 18.9200 兼容 WebKit 537.36 ?Chrome 70?
UserAgent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.9200

當(dāng)前Edge內(nèi)核版本:
內(nèi)核版本 (Version)?? ?WebKit 537.36 ?Chrome 111.0.0.0
UserAgent: 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

WebView2內(nèi)核版本:
內(nèi)核版本 (Version)?? ?WebKit 537.36 ?Chrome 111.0.0.0
UserAgent: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.51

可見,WebView2內(nèi)核版本跟Edge一樣,能順利打開視頻網(wǎng)站。WebBrowser內(nèi)核版本過低。

WebView2加載視頻網(wǎng)站
c# 通過webView2模擬登陸小紅書網(wǎng)頁版,解析無水印視頻圖片,以及解決X-s,X-t簽名驗證【2023年4月29日】

3.WebView2概述
? Microsoft Edge WebView2 控件允許在本機應(yīng)用中嵌入 web 技術(shù)(HTML、CSS 以及 JavaScript)。 WebView2 控件使用 Microsoft Edge 作為繪制引擎,以在本機應(yīng)用中顯示 web 內(nèi)容。
雖說無法跨平臺,但是在windows應(yīng)用下做為原瀏覽器控件替代品還是不錯的。

4.安裝webview2
? ?打開NuGet,搜索WebView2,安裝之后,可以看到左側(cè)就有了webview2控件,可以直接拖到窗體內(nèi)。

二、問題分析
1、關(guān)于登陸會話的問題
網(wǎng)頁端必須打開小紅書網(wǎng)站。小紅書打開后,在瀏覽器Cookie里,有一個字段:
web_session=040069b3b3f6625dade26f8d1d364b44f72186
這是記錄登陸會話信息的。請求時headers中需要x-s、x-t,cookie中需要有web_session。
經(jīng)測試,這個web_session會在瀏覽器保存一段時間,具體多久還有待驗證(B站也有個類似的session,是一個月)。其它字段無關(guān)緊要。
不使用WebView2打開網(wǎng)站的話,需要到網(wǎng)站申請web_session,這里WebView2已經(jīng)替我們弄好了。
通過c# WebView2獲取cookie信息的方法:

private Dictionary<string, string> mCookies = new Dictionary<string, string>();//保存Cookie到字典中

/// <summary>
        /// WebView2異步獲取cookie
        /// </summary>
        /// <param name="url">與cookie關(guān)聯(lián)的域名</param>
        private async void getCookie(string url)
        {
            List<CoreWebView2Cookie> cookieList = await webView.CoreWebView2.CookieManager.GetCookiesAsync(url);
            mCookies.Clear();
            for (int i = 0; i < cookieList.Count; ++i)
            {
                CoreWebView2Cookie cookie = webView.CoreWebView2.CookieManager.CreateCookieWithSystemNetCookie(cookieList[i].ToSystemNetCookie());
                mCookies.Add(cookie.Name, cookie.Value);
            }

        }

        /// <summary>
        /// 提取cookie中的一個字段;
        /// </summary>
        /// <param name="url">域名</param>
        /// <param name="key">關(guān)鍵字,如:web_session</param>
        /// <param name="t">延時(沒用到)</param>
        /// <returns></returns>
        public string getCookieEx(string url, string key, int t)
        {
            getCookie(url);
            if (mCookies.ContainsKey(key))
            {
                string cookies = "";
                foreach (var cookie in mCookies)
                {
                    cookies += cookie.Key + "=" + cookie.Value + ";";
                }
                cookies = key + "=" + mCookies[key];
                return cookies;
            }


            return null;
        }

2.筆記信息接口

目前筆記信息接口: /api/sns/web/v1/feed
請求時headers中需要x-s、x-t,cookie中需要有web_session。

3.X-S
定位方法很多,可以全局搜 "X-s" 。往上找可以發(fā)現(xiàn)該段為 sign 方法,function sign(e, t) {}

全部復(fù)制到本地,然后根據(jù)報錯把缺的方法和環(huán)境補一下,比如a0_0x4dee00、a0_0x5c27、a0_0x543e等方法,

然后把常用的navigator、location、document、window加上就好了。

該過程中根據(jù)具體錯誤再調(diào)試分析, 比如sign方法的 case "6",修改為var vr = window 、在case "7"中可以手動修改為 dr = ur['sNYMU']
這里已經(jīng)拿到了function sign(e, t) {}的JavaScript版,需要的+v:byc6352

三.解析原理及流程

? 1、獲取小紅書筆記分享鏈接
Meta發(fā)布了一篇小紅書筆記,快來看吧! ?? 95mtho0hHhZLd1q ?? http://xhslink.com/AKXMyp,復(fù)制本條信息,打開【小紅書】App查看精彩內(nèi)容!
? 2、執(zhí)行url重定向得到帶來note_id的新鏈接
https://www.xiaohongshu.com/discovery/item/6430e99c00000000140259d3?app_platform=android&amp;app_version=7.83.0&amp;share_from_user_hidden=true&amp;type=video&amp;xhsshare=CopyLink&amp;appuid=640d1628000000001400dc4d&amp;apptime=1682740972
? 3、解析出note_id
note_id=6430e99c00000000140259d3
? 4、調(diào)用JavaScript function sign(e, t) 簽名得到X-s,X-t
X-t: 1682742221056
X-s: Ogsb02Zv0gUJO2w6OB4UOjTl1g9CsBT+Oj9W0gsK1g13

? 5、發(fā)送post請求:
? ?(1)數(shù)據(jù):

var args = '{\"source_note_id\":\"' + note_id + '\"}';


? (2)請求頭(不會的+v:byc6352):

//JavaScript代碼:
var headers = 'X-t: ' + o['X-t'] + '\r\nX-s: ' + o['X-s'] + '\r\nContent-Type: application/json;charset=UTF-8\r\nReferer: https://www.xiaohongshu.com/\r\nCookie: ' + cookie;?


? (3)服務(wù)器接口:

//JavaScript代碼:
var api_url = 'https://edith.xiaohongshu.com/api/sns/web/v1/feed';


? (4)發(fā)送post:

//JavaScript代碼:
var data = winning.getPostResult(api_url, args, headers);


? (5)得到筆記信息數(shù)據(jù)(json):

{"msg":"成功","data":{"cursor_score":"","items":[{"id":"6430e99c00000000140259d3","model_type":"note","note_card":{"at_user_list":[],"last_update_time":1680927132000,"title":"幻晝#治愈系風(fēng)景","desc":"","user":{"user_id":"62c7b52a000000000303fdb4","nickname":"Meta","avatar":"https://sns-avatar-qc.xhscdn.com/avatar/62c7de8013ab526ecfbf1777.jpg"},"interact_info":{"share_count":"1","followed":false,"liked":false,"liked_count":"3","collected":false,"collected_count":"2","comment_count":"0"},"image_list":[{"file_id":"4e8ce0b1-ba6f-83bf-646b-bf8fea89341f","height":1280,"width":720,"url":"https://sns-img-hw.xhscdn.com/4e8ce0b1-ba6f-83bf-646b-bf8fea89341f","trace_id":"217/0/01e430e94079052e00100001875f0f3462_0.jpg"}],"tag_list":[],"time":1680927132000,"ip_location":"云南","note_id":"6430e99c00000000140259d3","share_info":{"un_share":false},"type":"video","video":{"media":{"video_id":136287668638655138,"video":{"drm_type":0,"stream_types":[259],"biz_name":110,"biz_id":"280402856711969235","duration":257,"md5":"5bb4036b378ab014d2114784bc147f10","hdr_type":0},"stream":{"h265":[],"av1":[],"h264":[{"audio_duration":250729,"master_url":"http://sns-video-hw.xhscdn.com/stream/110/259/01e430e99c7922a201037003875f169774_259.mp4","vmaf":-1,"stream_desc":"WM_X264_MP4","duration":256800,"size":68608344,"fps":30,"psnr":0,"ssim":0,"quality_type":"HD","height":1280,"avg_bitrate":2137331,"default_stream":0,"width":720,"video_duration":256800,"audio_bitrate":64035,"audio_channels":2,"backup_urls":["http://sns-video-bd.xhscdn.com/stream/110/259/01e430e99c7922a201037003875f169774_259.mp4","http://sns-video-qc.xhscdn.com/stream/110/259/01e430e99c7922a201037003875f169774_259.mp4?sign=6c5ffdf48d9c842405bb3e3a5fa361e7&t=644e8f54","http://sns-video-al.xhscdn.com/stream/110/259/01e430e99c7922a201037003875f169774_259.mp4"],"stream_type":259,"format":"mp4","volume":0,"video_codec":"h264","hdr_type":0,"rotate":0,"video_bitrate":2068304,"audio_codec":"aac","weight":62}]}},"image":{"thumbnail_fileid":"110/0/01e430e99c7922a200100001875f111ff3_0.webp"},"capa":{"duration":256},"consumer":{"origin_video_key":"spectrum/1000g2f02adqphsqh20005om7mkl0vvdklvh95l8"}}}}],"current_time":1682743347282},"code":0,"success":true}


? 6、解析筆記信息數(shù)據(jù)(json):
? 如果data.items[i].note_card.type='video' 說明該筆記為視頻內(nèi)容;
? 如果data.items[i].note_card.type='normal' 說明該筆記為圖文內(nèi)容;
? 7、一張圖看懂無水印視頻、無水印封面所在位置:
? PHOTO_HOST='https://sns-img-hw.xhscdn.com/'; ?//無水印封面服務(wù)器
? VIDEO_HOST='http://sns-video-bd.xhscdn.com/'; ?//無水印視頻服務(wù)器

c# 通過webView2模擬登陸小紅書網(wǎng)頁版,解析無水印視頻圖片,以及解決X-s,X-t簽名驗證【2023年4月29日】

?

四、WebView2中C#和JavaScript代碼互操作
?1.需要創(chuàng)建一個ScriptHost對象,并注冊到WebView2中:

    /// <summary>
    /// 網(wǎng)頁調(diào)用C#方法
    /// </summary>
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public class ScriptHost

2.在WebView2初始化完成事件中注冊ScriptHost對象

        /// <summary>
        /// CoreWebView2初始化完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void webView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
        {
            //注冊winning,winasync腳本c#互操作
            webView.CoreWebView2.AddHostObjectToScript("scriptHost", scriptHost);
            //注冊全局變量winning 同步操作;winasync:異步操作;
            webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("var winasync= window.chrome.webview.hostObjects.scriptHost;");
            webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("var winning= window.chrome.webview.hostObjects.sync.scriptHost;");
        }

3.ScriptHost中暴露的公共方法,都可以在前端JavaScript中調(diào)用。

        /// <summary>
        /// 日志記錄(JavaScript前端調(diào)用
        /// </summary>
        /// <param name="message">JavaScript前端信息</param>
        public void log(string message)
        {
            Log.i(message);//記錄到文本文件中
            //MessageBox.Show(message);
        }
..............................................
winning.log(data);//JavaScript端調(diào)用(同步調(diào)用);

五、下載封面及視頻


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Configuration;
using System.Text;
using System.Threading.Tasks;

namespace XhsVideo
{
    /// <summary>
    /// 下載視頻
    /// </summary>
    internal class VideoDown
    {
        public int id { get; set; }
        public VideoInfo video { get; set; }
        public string savedir { get; set; }
        public string msg { get; set; }
        public bool success { get; set; }
        public string headers { get; set; }
        public VideoDown(int id,VideoInfo video,string savdir,string headers=null) {
            this.id = id;
            this.video = video;
            this.savedir = savdir;
            if (System.IO.Directory.Exists(savdir)) System.IO.Directory.CreateDirectory(savdir);
            this.headers = headers;
        }
        public void process()
        {
            string filename = MakeValidFileName( video.title,"");  //去除文件名中的非法字符
            string videoname = savedir + "\\" + filename + ".mp4";
            string covername = savedir + "\\" + filename + ".webp";
            if (System.IO.File.Exists(covername)) System.IO.File.Delete(covername);
            if (System.IO.File.Exists(videoname)) System.IO.File.Delete(videoname);
            Log.i(videoname);
            Log.i(covername);
            //NetHelper.downloadfileAsync(video.videoUrl, videoname);
            NetHelper.downloadfileAsync(video.coverUrl, covername);
            NetHelper.DownloadFileAsync(video.videoUrl, videoname, showProgress);//顯示下載視頻的進度
        }






        /**
            * @param text: 原始串
            * @param replacement: 要替換的字符串
        */
        public static string MakeValidFileName(string text, string replacement = "_")
        {
            StringBuilder str = new StringBuilder();
            var invalidFileNameChars = System.IO.Path.GetInvalidFileNameChars();
            foreach (var c in text)
            {
                if (invalidFileNameChars.Contains(c))
                {
                    str.Append(replacement ?? "");
                }
                else
                {
                    str.Append(c);
                }
            }

            return str.ToString();
        }
        /// <summary>
        /// 下載視頻的進度回調(diào)函數(shù)
        /// </summary>
        /// <param name="msg">下載進度信息</param>
        public void showProgress(string msg)
        {
            this.msg = msg;
            Log.i(msg);
            fMainForm.GetFMainForm().syncContext.Send(fMainForm.GetFMainForm().SetTextSafePost, this);//Post 將信息發(fā)送到窗體顯示

        }

    }


    /// <summary>
    /// 視頻信息類,由:標(biāo)題,封面地址,視頻地址組成。
    /// </summary>

    public class VideoInfo
    {
        public string title { get; set; }
        public string coverUrl { get; set; }
        public string videoUrl { get; set; }
        public VideoInfo(string title,string coverUrl,string videoUrl)
        {
            this.title = title;
            this.coverUrl = coverUrl;
            this.videoUrl = videoUrl;
        }
    }
}

六、日志記錄


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XhsVideo
{
    /// <summary>
    /// 日志記錄 到文本文件
    /// </summary>
    internal class Log
    {
        private static  Log log;
        private static string logName;
        private Log(string filename) {
            logName = filename;
        }
        public static Log GetLog(string filename)
        {
            if (log == null) { log = new Log(filename); }
            return log;
        }
        public static Log GetLog()
        {
            return log;
        }
        public static void i(string msg)
        {
            string now = DateTime.Now.ToString();
            string[] text = new string[2];
            text[0] = now;
            text[1] = msg;
            try
            {
                using (StreamWriter sw = new StreamWriter(logName,true,Encoding.UTF8))
                {
                    foreach (string s in text)
                    {
                        sw.WriteLine(s);

                    }
                    sw.Close();
                }
                
            }
            catch (Exception e)
            {
                //Console.WriteLine("Exception: " + e.Message);
            }
            finally
            {
                //Console.WriteLine("Executing finally block.");
            }
        }
    }
}

七、網(wǎng)絡(luò)訪問組件


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.IO;
using System.Windows.Forms;

namespace XhsVideo
{
    /// <summary>
    /// 網(wǎng)絡(luò)訪問組件
    /// </summary>
    internal class NetHelper
    {

        #region 文件下載
        /// <summary>
        /// 下載文件
        /// </summary>
        /// <param name="url">文件下載地址</param>
        /// <param name="savePath">本地保存路徑+名稱</param>
        /// <param name="downloadCallBack">下載回調(diào)(總長度,已下載,進度)</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static async Task DownloadFileAsync(string url, string savePath, Action<string> downloadCallBack = null)
        {
            try
            {
                downloadCallBack?.Invoke($"文件【{url}】開始下載!");
                HttpResponseMessage response = null;
                using (HttpClient client = new HttpClient())
                    response = await client.GetAsync(url);
                if (response == null)
                {
                    downloadCallBack?.Invoke("文件獲取失敗");
                    return;
                }
                var total = response.Content.Headers.ContentLength ?? 0;
                var stream = await response.Content.ReadAsStreamAsync();
                var file = new FileInfo(savePath);
                using (var fileStream = file.Create())
                using (stream)
                {
                    if (downloadCallBack == null)
                    {
                        await stream.CopyToAsync(fileStream);
                        downloadCallBack?.Invoke($"文件【{url}】下載完成!");
                    }
                    else
                    {
                        byte[] buffer = new byte[1024];
                        long readLength = 0;
                        int length;
                        double temp = 0;
                        string msg = "";
                        while ((length = await stream.ReadAsync(buffer, 0, buffer.Length)) != 0)
                        {
                            // 寫入到文件
                            fileStream.Write(buffer, 0, length);

                            //更新進度
                            readLength += length;
                            double progress = Math.Round((double)readLength / total * 100, 2, MidpointRounding.AwayFromZero);//.ToZero

                            if ((progress % 1) == 0 && (progress % 1) != temp)
                            { 
                                msg = $"總大?。骸緖total}】,已下載:【{readLength}】,進度:【{progress}】";
                                downloadCallBack?.Invoke(msg);
                            }
                            temp = progress % 1;
                            //下載完畢立刻關(guān)閉釋放文件流
                            if (total == readLength && progress == 100)
                            {
                                fileStream.Close();
                                fileStream.Dispose();
                                msg = $"總大小:【{total}】,已下載:【{readLength}】,進度:【{progress}】下載完成。";
                                downloadCallBack?.Invoke(msg);
                            }


                        }
                    }
                }
            }
            catch (Exception ex)
            {
                downloadCallBack?.Invoke($"下載文件失敗:{ex.Message}!");
            }
        }
        #endregion




        /// <summary>
        /// 異步下載文件
        /// </summary>
        /// <param name="url"></param>
        /// <param name="filename"></param>
        public static async void downloadfileAsync(string url,string filename)
        {
            using (var web = new WebClient())
            {
                await web.DownloadFileTaskAsync(url, filename);
            }
        }
      
        /// <summary>
        /// 地址重定向
        /// </summary>
        /// <param name="url">原地址</param>
        /// <param name="domain">域名</param>
        /// <param name="ua">userAgent</param>
        /// <returns>重定向后的地址</returns>
        public static string getRedirectedUrl(string url, string domain, string ua)
        {
            var str = getRedirectedUrl_T(url);
            return str.Result;
        }
        /// <summary>
        /// 異步地址重定向
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private static async Task<string> getRedirectedUrl_T(string url)
        {
            try
            {
                var handler = new HttpClientHandler()
                {
                    AllowAutoRedirect = false
                };
                var client = new HttpClient(handler);

                var response = await client.GetAsync(url).ConfigureAwait(continueOnCapturedContext: false);
                int statuscode = (int)response.StatusCode;
                if (statuscode == 307)
                {
                    string location = response.Headers.Location.ToString();
                    return location;
                }
                if (statuscode == 302)
                {
                    string location = response.Headers.Location.ToString();
                    return location;
                }
                else
                {
                    return "";
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("getRedirectedUrl_T:" + e.ToString());
                return "";
            }
        }
        //---------------------------------------------------------------post---------------------------------------------------------------------
        /// <summary>
        /// Post訪問
        /// </summary>
        /// <param name="url">訪問地址</param>
        /// <param name="args">數(shù)據(jù)</param>
        /// <param name="headers">HTTP頭</param>
        /// <returns>返回服務(wù)器JSON數(shù)據(jù)</returns>
        public static string getPostResult(string url, string args, string headers)
        {
            var str = getPostResult_T(url, args, headers);
            return str.Result;
        }
        /// <summary>
        /// 異步post調(diào)用
        /// </summary>
        /// <param name="url"></param>
        /// <param name="args"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        private static async Task<string> getPostResult_T(string url, string args, string headers)
        {
            try
            {
                var handler = new HttpClientHandler() { UseCookies = false };
                var client = new HttpClient(handler);// { BaseAddress = baseAddress };
                client.Timeout = TimeSpan.FromSeconds(20);
                var message = new HttpRequestMessage(HttpMethod.Post, url);
                message.Content = new StringContent(args);
                message.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                //message.Headers;
                Dictionary<string, string> dictionary = ParseToDictionary(headers);
                foreach (var pair in dictionary)
                {
                    if (pair.Key.Equals("content-type")) continue;
                    if (pair.Key.Equals("Content-Type")) continue;
                    message.Headers.Add(pair.Key, pair.Value);
                }

                var result = await client.SendAsync(message).ConfigureAwait(continueOnCapturedContext: false);
                result.EnsureSuccessStatusCode();
                return await result.Content.ReadAsStringAsync();
            }
            catch (Exception e)
            {
                //EventLog.GetEventLogs(e.ToString);
                System.Diagnostics.Debug.WriteLine("getPostResultEx_T:" + e.ToString());
                ///console.write(e.ToString());
                return "";
            }
        }
        
        /// <summary>
        /// 字符串解析為字典數(shù)據(jù)
        /// </summary>
        /// <param name="str">以回車換行符分割的字符串</param>
        /// <returns>字典數(shù)據(jù)</returns>
        private static Dictionary<string, string> ParseToDictionary(string str)
        {
            Dictionary<string, string> result = new Dictionary<string, string>();
            string str1 = str;
            int i = str1.IndexOf("\r\n");
            int j = 0;
            while (i > 0)
            {
                string str2 = str1.Substring(0, i);
                j = str2.IndexOf(":");
                if (j > 0)
                {
                    string str21 = str2.Substring(0, j);
                    string str22 = str2.Substring(j + 1);
                    result.Add(str21, str22);
                }
                str1 = str1.Substring(i + 2);
                i = str1.IndexOf("\r\n");
            }
            j = str1.IndexOf(":");
            if (j > 0)
            {
                string str21 = str1.Substring(0, j);
                string str22 = str1.Substring(j + 1);
                result.Add(str21, str22);
            }
            return result;
        }
        //-------------------------------------------------------------------GET -------------------------------------------------------------------
        /// <summary>
        /// 獲取服務(wù)器端的HTML代碼
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string getHtmlCode(string url)
        {
            var str = getHtmlCode_T(url);
            return str.Result;
        }
        /// <summary>
        /// 異步獲取服務(wù)器端的HTML代碼
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static async Task<string> getHtmlCode_T(string url)
        {
            try
            {
                var http = new HttpClient();
                http.Timeout = TimeSpan.FromSeconds(10);
                var result = await http.GetStringAsync(url).ConfigureAwait(continueOnCapturedContext: false);
                return result;
            }
            catch (Exception e)
            {
                //EventLog.GetEventLogs(e.ToString);
                System.Diagnostics.Debug.WriteLine("錯誤信息在這兒:" + e.ToString());
                ///console.write(e.ToString());
                Log.i(e.ToString());
                return "";
            }
        }

    }
}

八、ScriptHost與JavaScript交互(主要流程):

using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using System.Threading;
using System.Security.Policy;
using System.Net.Http;
using System.Net.Http.Headers;

namespace XhsVideo
{
    /// <summary>
    /// 網(wǎng)頁調(diào)用C#方法
    /// </summary>
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public class ScriptHost
    {
        
        private WebView2 webView;
        private Dictionary<string, string> mCookies = new Dictionary<string, string>();//保存Cookie到字典中
        private string mUrl;
        public static ScriptHost scriptHost = null;
        private ScriptHost(WebView2 webView)
        {
            scriptHost = this;
            this.webView = webView;
            //注冊事件偵聽,加載頁面完成時,獲取cookie;
            this.webView.NavigationCompleted += new System.EventHandler<Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs>(this.webView_NavigationCompleted);
            //webView初始化完成后注冊與JavaScript交互
            this.webView.CoreWebView2InitializationCompleted += new System.EventHandler<Microsoft.Web.WebView2.Core.CoreWebView2InitializationCompletedEventArgs>(this.webView_CoreWebView2InitializationCompleted);
        }
        public static ScriptHost GetScriptHost(WebView2 webView)
        {
            if (scriptHost == null) scriptHost = new ScriptHost(webView);
            return scriptHost;
        }
        /// <summary>
        /// 日志記錄(JavaScript前端調(diào)用
        /// </summary>
        /// <param name="message">JavaScript前端信息</param>
        public void log(string message)
        {
            Log.i(message);//記錄到文本文件中
            //MessageBox.Show(message);
        }
        /// <summary>
        /// 提取cookie中的一個字段;
        /// </summary>
        /// <param name="url">域名</param>
        /// <param name="key">關(guān)鍵字,如:web_session</param>
        /// <param name="t">延時(沒用到)</param>
        /// <returns></returns>
        public string getCookieEx(string url, string key, int t)
        {
            getCookie(url);
            if (mCookies.ContainsKey(key))
            {
                string cookies = "";
                foreach (var cookie in mCookies)
                {
                    cookies += cookie.Key + "=" + cookie.Value + ";";
                }
                cookies = key + "=" + mCookies[key];
                //cookies = "web_session=040069b3b3f6625dade26f8d1d364b44f72186";
                return cookies;
            }


            return null;
        }
        /// <summary>
        /// WebView2異步獲取cookie
        /// </summary>
        /// <param name="url">與cookie關(guān)聯(lián)的域名</param>
        private async void getCookie(string url)
        {
            List<CoreWebView2Cookie> cookieList = await webView.CoreWebView2.CookieManager.GetCookiesAsync(url);
            mCookies.Clear();
            for (int i = 0; i < cookieList.Count; ++i)
            {
                CoreWebView2Cookie cookie = webView.CoreWebView2.CookieManager.CreateCookieWithSystemNetCookie(cookieList[i].ToSystemNetCookie());
                mCookies.Add(cookie.Name, cookie.Value);
            }

        }
        /// <summary>
        /// 解析并下載由JavaScript返回的信息
        /// </summary>
        /// <param name="text"></param>
        public void getJsResult(string text)
        {
            Log.i(text);
            string temp = text;
            string[] ss = text.Split(',');
            string title = "";
            string coverUrl = "";
            string videoUrl = "";
            string origin_video_key = "";
            string trace_id = "";
            int id = 0;
            foreach (string s in ss)
            {
                string[] dd = s.Split('=');
                if (dd.Length == 2)
                {
                    if (dd[0].Equals("title")) title = dd[1];
                    if (dd[0].Equals("cover_url")) coverUrl = dd[1];
                    if (dd[0].Equals("video_url")) videoUrl = dd[1];
                    if (dd[0].Equals("origin_video_key")) origin_video_key = dd[1];
                    if (dd[0].Equals("trace_id")) trace_id = dd[1];
                    if (dd[0].Equals("id")) id = int.Parse(dd[1]);
                }
           
            }
            videoUrl = "http://sns-video-hw.xhscdn.com/" + origin_video_key;//無水印視頻
            coverUrl = "https://sns-img-qc.xhscdn.com/" + trace_id;//無水印封面
            VideoInfo video = new VideoInfo(title, coverUrl, videoUrl);//創(chuàng)建視頻信息對象
            VideoDown videodown=new VideoDown(id, video, Config.savedir);//創(chuàng)建視頻下載對象
            videodown.process();//執(zhí)行下載


        }
        //---------------------------------------------------------socket--------------------------------------------------------------------------------
        /// <summary>
        /// 重定向鏈接,該方法由JavaScript調(diào)用;
        /// </summary>
        /// <param name="url"></param>
        /// <param name="domain"></param>
        /// <param name="ua"></param>
        /// <returns></returns>
        public string getRedirectedUrl(string url, string domain, string ua)
        {
            return NetHelper.getRedirectedUrl(url, domain, ua);
        }
        /// <summary>
        /// 提交post請求,該方法由JavaScript調(diào)用;
        /// </summary>
        /// <param name="url"></param>
        /// <param name="args"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public string getPostResultEx(string url, string args, string headers)
        {
            return NetHelper.getPostResult(url, args, headers);
        }
        //-----------------------------------------------------------事件---------------------------------------------------------------------------
        /// <summary>
        /// 加載完頁面時,獲取cookie
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void webView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
        {

            string url = webView.Source.Host.ToString();
            url = "https://" + url;
            getCookie(url);
        }
        /// <summary>
        /// CoreWebView2初始化完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void webView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
        {
            //注冊winning,winasync腳本c#互操作
            webView.CoreWebView2.AddHostObjectToScript("scriptHost", scriptHost);
            //注冊全局變量winning 同步操作;winasync:異步操作;
            webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("var winasync= window.chrome.webview.hostObjects.scriptHost;");
            webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("var winning= window.chrome.webview.hostObjects.sync.scriptHost;");
        }
    }
}

因為涉及的技術(shù)知識點太多了,后續(xù)繼續(xù)完善下載無水印圖文。

c# 通過webView2模擬登陸小紅書網(wǎng)頁版,解析無水印視頻圖片,以及解決X-s,X-t簽名驗證【2023年4月29日】
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(未完待續(xù))文章來源地址http://www.zghlxwxcb.cn/news/detail-447281.html

到了這里,關(guān)于c# 通過webView2模擬登陸小紅書網(wǎng)頁版,解析無水印視頻圖片,以及解決X-s,X-t簽名驗證【2023年4月29日】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • C# Winform 中使用 Webview2

    目前的windows/Linux下的UI方案,以Qt為主,F(xiàn)lutter, Electron為輔,其他的各種UI都是不堪大用。眾所周知,Electron的資源占用和內(nèi)容占用太大,效率不行,所以有了后續(xù)各種跨語言的Web套殼方案: walls go語言下web套殼 tarui Rust下的web套殼 除了使用CEF的Qt/C++/C#方案,Qt+WebEngine, 目前在

    2024年02月12日
    瀏覽(21)
  • VBS加載微軟網(wǎng)頁控件webview2(Edge-Chromium谷歌內(nèi)核)

    VBS加載微軟網(wǎng)頁控件webview2(Edge-Chromium谷歌內(nèi)核)

    VBS加載微軟網(wǎng)頁控件webview2(Edge-Chromium谷歌內(nèi)核) VBA加載Webview2瀏覽器內(nèi)核 代替了ie的webbrowser控件,效果類似: 資源:VBS加載webview2控件代替ie的webbrowser(Edge-Chromium谷歌內(nèi)核)資源-CSDN文庫 VBS loads the Microsoft web control webview2 (edge ??Google kernel)Instead of the webbrowser control of ie, the e

    2024年02月06日
    瀏覽(23)
  • c#使用webView2 訪問本地靜態(tài)html資源跨域Cors問題

    c#使用webView2 訪問本地靜態(tài)html資源跨域Cors問題

    在瀏覽器中訪問本地靜態(tài)資源html網(wǎng)頁時,可能會遇到跨域問題如圖。 ? 是因為瀏覽器默認啟用了同源策略,即只允許加載與當(dāng)前網(wǎng)頁具有相同源(協(xié)議、域名和端口)的內(nèi)容。 WebView2默認情況下啟用了瀏覽器的同源策略,即只允許加載與主機相同源的內(nèi)容。所以如果我們把

    2024年02月20日
    瀏覽(27)
  • 【小沐學(xué)C++】C++ MFC中嵌入web網(wǎng)頁控件(WebBrowser、WebView2、CEF3)

    【小沐學(xué)C++】C++ MFC中嵌入web網(wǎng)頁控件(WebBrowser、WebView2、CEF3)

    WebBrowser控件最常見的用途之一是向應(yīng)用程序添加 Internet 瀏覽功能。使用 IWebBrowser2 接口,可以瀏覽到本地文件系統(tǒng)、網(wǎng)絡(luò)或萬維網(wǎng)上的任何位置??梢允褂肐WebBrowser2::Navigate 方法告知控件要瀏覽到哪個位置。第一個參數(shù)是包含位置名稱的字符串。要瀏覽到本地文件系統(tǒng)或網(wǎng)絡(luò)

    2024年02月05日
    瀏覽(93)
  • c#使用webView2 訪問本地靜態(tài)html資源跨域Cors問題 (附帶代理服務(wù)helper幫助類)

    c#使用webView2 訪問本地靜態(tài)html資源跨域Cors問題 (附帶代理服務(wù)helper幫助類)

    在瀏覽器中訪問本地靜態(tài)資源html網(wǎng)頁時,可能會遇到跨域問題如圖。 ? 是因為瀏覽器默認啟用了同源策略,即只允許加載與當(dāng)前網(wǎng)頁具有相同源(協(xié)議、域名和端口)的內(nèi)容。 WebView2默認情況下啟用了瀏覽器的同源策略,即只允許加載與主機相同源的內(nèi)容。所以如果我們把

    2024年02月21日
    瀏覽(26)
  • WPF混合開發(fā)之WebView2(二) WebView2的簡單使用

    WPF混合開發(fā)之WebView2(二) WebView2的簡單使用

    在上一篇文章中,我們介紹了WebView2的環(huán)境搭建,點此前往,在這一章節(jié),我們將使用WebView2簡單搭建一個WPF程序,在程序中加載百度搜索頁面,廢話不多說,直接上流程。 建立WPF工程 建立WPF工程步驟很簡單,在此不再截圖,直接上步驟: 打開Visual Stido 2022(博主使用的是vs

    2024年02月05日
    瀏覽(22)
  • 零基礎(chǔ)學(xué)鴻蒙編程-通過WebView打開網(wǎng)頁

    零基礎(chǔ)學(xué)鴻蒙編程-通過WebView打開網(wǎng)頁

    WebView是用來打開網(wǎng)頁的一種UI控件,可以在App內(nèi)跳轉(zhuǎn)到指定網(wǎng)址,而不是采用系統(tǒng)瀏覽器打開網(wǎng)頁. activity 布局文件ability_main.xml: 增加權(quán)限 修改config.json,添加如下權(quán)限: https://gitee.com/hspbc/harmonyos_demos/tree/master/webviewDemo 《零基礎(chǔ)學(xué)安卓編程》 《零基礎(chǔ)學(xué)Java編程》 《零基礎(chǔ)學(xué)鴻

    2024年02月13日
    瀏覽(16)
  • WPF中使用WebView2控件

    WPF中使用WebView2控件

    WebView2 全稱 Microsoft Edge WebView2 控件,此控件的作用是在本機桌面應(yīng)用中嵌入web技術(shù)(html,css,javascript),從名字就可以看出來WebView2使用了Edge內(nèi)核渲染web內(nèi)容。 通俗來說,WebView2控件是一個UI組件,允許在桌面應(yīng)用中提供web能力的集成,即俗稱的混合開發(fā)。 助力程序開發(fā)和

    2024年02月03日
    瀏覽(63)
  • WebView2 的初步集成與試用

    WebView2 的初步集成與試用

    目錄 一、環(huán)境概況 二、安裝 三、集成測試 ?參考資料 ? ? ? ? 由于以前公司自己集成了一個瀏覽器供客戶使用,而原來的瀏覽器使用的是IWebBrowser2的技術(shù),而IWebBrowser2技術(shù)支持的IE框架只能到ie11,但由于現(xiàn)在新的js框架橫行,而且加上windows放棄了IE瀏覽器,而有的客戶項目

    2024年02月05日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包