You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用RestSharp的Async异步方法批量爬取多个URL并填充Data类的Html属性?

我来帮你搞定这个批量异步爬取的问题,直接上修改后的完整方案和关键细节解释:

核心修改思路

原代码只处理了列表第一个元素,我们需要遍历所有Data对象,为每个对象创建异步爬取任务,然后并行执行并等待所有任务完成,同时优化RestClient的使用方式提升性能,还要处理URL编码避免请求错误。

修改后的完整代码

public class Data 
{ 
    public int Id { get; set; } 
    public string Url { get; set; } 
    public string Html { get; set; } 
    public static List<Data> Datas = new List<Data>(); 
}

class Program 
{ 
    // 复用RestClient(RestSharp最佳实践,减少连接开销)
    private static readonly RestClient _restClient = new RestClient();

    // 改用async Main(.NET Core 3.0+支持,更优雅的异步入口)
    static async Task Main(string[] args) 
    { 
        // 生成10条测试数据
        for (int i = 0; i < 10; i++) 
        { 
            Data.Datas.Add(new Data { Id = i, Url = "https://www.httpbin.org", Html = null, }); 
        } 

        // 执行批量爬取
        await DoScrapeAllAsync(); 

        Console.WriteLine("✅ 所有爬取任务完成!");
        // 可选:验证结果,打印前3条数据的HTML长度
        foreach (var data in Data.Datas.Take(3))
        {
            Console.WriteLine($"数据ID {data.Id} | HTML内容长度: {data.Html?.Length ?? 0}");
        }
        Console.ReadLine(); 
    } 

    static async Task DoScrapeAllAsync() 
    { 
        // 为每个Data对象创建独立的爬取任务
        var scrapeTasks = Data.Datas.Select(scrapeSingleData).ToList();
        
        // 等待所有异步任务全部完成
        await Task.WhenAll(scrapeTasks);
    }

    // 单独处理单个Data对象的爬取逻辑
    static async Task scrapeSingleData(Data dataItem)
    {
        try
        {
            // 构建带ScraperAPI的请求URL,必须对目标URL编码避免格式错误
            var targetUrl = $"{dataItem.Url}/ip";
            var requestUrl = $"http://api.scraperapi.com/?api_key=c3df2_fake_4d5e&url={Uri.EscapeDataString(targetUrl)}&country_code=us";
            
            var req = new RestRequest(requestUrl, Method.GET); 
            var htmlContent = await _restClient.GetAsync<string>(req); 
            
            // 将爬取结果赋值给对应Data对象的Html属性
            dataItem.Html = htmlContent; 
            Console.WriteLine($"✅ 完成爬取 数据ID {dataItem.Id}");
        }
        catch (Exception ex)
        {
            // 可选:添加异常处理,避免单个请求失败导致全部任务终止
            Console.WriteLine($"❌ 爬取数据ID {dataItem.Id} 失败: {ex.Message}");
        }
    }
}

关键细节说明

  1. 并行异步处理:

    • 用Data.Datas.Select(scrapeSingleData)为每个Data生成异步任务,再通过Task.WhenAll等待所有任务完成,所有请求并行执行,效率远高于逐个同步处理。
  2. RestClient复用:

    • RestClient内部维护了HTTP连接池,全局复用一个实例可以减少TCP连接的创建销毁开销,大幅提升性能,这是RestSharp官方推荐的最佳实践。
  3. URL编码:

    • 用Uri.EscapeDataString对目标URL进行编码,确保URL中的特殊字符(比如&、=)不会破坏请求URL的结构,避免请求失败。
  4. 优雅的异步入口:

    • .NET Core 3.0+支持async Main,直接用await等待爬取任务,替代原代码的空循环等待,既优雅又避免CPU空转。如果是.NET Framework项目,可以把Main改成:
      static void Main(string[] args)
      {
          // ...生成测试数据
          DoScrapeAllAsync().Wait();
          // ...后续逻辑
      }
      
  5. 可选的并发控制:
    如果担心请求过于频繁被目标网站或ScraperAPI限制,可以用SemaphoreSlim限制并发数(比如最多5个同时请求),修改DoScrapeAllAsync方法即可:

    static async Task DoScrapeAllAsync() 
    { 
        // 限制最多5个并发请求
        using var semaphore = new SemaphoreSlim(5);
        var scrapeTasks = Data.Datas.Select(async dataItem =>
        {
            await semaphore.WaitAsync();
            try
            {
                await scrapeSingleData(dataItem);
            }
            finally
            {
                semaphore.Release();
            }
        }).ToList();
        
        await Task.WhenAll(scrapeTasks);
    }
    

内容的提问来源于stack exchange,提问作者John Brk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 11:17:37