IronWebScraper在ASP.NET C# WebAPI中不触发Parse方法问题咨询
根本原因
IronWebScraper的Start()方法默认是非阻塞的异步后台执行,你在API控制器的Action方法中初始化scraper实例并调用Start()后,方法立即返回响应,当前请求上下文结束后,本地的scraper实例没有被任何根对象引用,很快就会被GC回收,此时站点发起的爬取请求还没有收到响应,自然无法触发Parse回调方法。
而你放在Application_Start中初始化的scraper实例是全局存活的,没有被回收的风险,因此可以正常接收响应触发Parse方法。
解决方案
根据你的业务场景可以选择以下两种方案:
方案1:等待爬取任务完成后再返回响应
如果接口需要等爬取结束再返回结果,调用Start()后追加等待逻辑,确保爬取任务全部完成前scraper实例不会被回收:
public dynamic ScrapTest() { try { var scraper = new HelloScraper(); scraper.Start(); // 等待所有爬取请求处理完成,最长等待时间可自定义,单位毫秒 scraper.WaitForAllRequestsComplete(30000); return new { code = 1, msg = "OK", // 可在这里返回爬取结果 }; } catch (Exception ex) { // 日志处理 } return new { code = -1, msg = "Error" }; }
如果是异步接口,可以直接用异步API避免线程阻塞:
public async Task<dynamic> ScrapTest() { try { var scraper = new HelloScraper(); await scraper.StartAsync(); return new { code = 1, msg = "OK" }; } catch (Exception ex) { // 日志处理 } return new { code = -1, msg = "Error" }; }
方案2:后台异步爬取无需等待返回
如果接口不需要返回爬取结果,只需要触发爬取任务,需要确保scraper实例不会被GC回收:
- 将scraper注册为DI容器的单例服务,全局复用同一个实例
- 或者用静态变量存储scraper实例,避免被回收
示例代码:
// 全局静态变量存储实例 public static class ScraperHolder { public static HelloScraper Scraper { get; set; } } // Global.asax中初始化一次 void Application_Start(object sender, EventArgs e) { AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); RouteConfig.RegisterRoutes(RouteTable.Routes); ScraperHolder.Scraper = new HelloScraper(); } // 控制器中直接调用 public dynamic ScrapTest() { try { ScraperHolder.Scraper.Start(); return new { code = 1, msg = "OK" }; } catch (Exception ex) { // 日志处理 } return new { code = -1, msg = "Error" }; }
额外注意事项
- IronWebScraper的授权激活操作必须在应用启动阶段全局执行一次,不要在控制器中每次请求都重复激活
- 如果爬取站点有反爬限制,不要每次接口请求都新建scraper实例,避免IP被封禁
内容的提问来源于stack exchange,提问作者Clark Serven
相关产品推荐
相关产品推荐

