上一篇(https://www.cnblogs.com/meowv/p/12971041.html)使用HtmlAgilityPack抓取壁纸数据成功将图片存入数据库,本篇继续来完成一个全网各大平台的热点新闻数据的抓取。

同样的,可以先预览一下我个人博客中的成品:https://meowv.com/hot ,和抓取壁纸的套路一样,大同小异。

本次要抓取的源有18个,分别是博客园、V2EX、SegmentFault、掘金、微信热门、豆瓣精选、IT之家、36氪、百度贴吧、百度热搜、微博热搜、知乎热榜、知乎日报、网易新闻、GitHub、抖音热点、抖音视频、抖音正能量。

还是将数据存入数据库,按部就班先将实体类和自定义仓储创建好,实体取名HotNews。贴一下代码:

//HotNews.cs
using System;
using Volo.Abp.Domain.Entities; namespace Meowv.Blog.Domain.HotNews
{
public class HotNews : Entity<Guid>
{
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; } /// <summary>
/// 链接
/// </summary>
public string Url { get; set; } /// <summary>
/// SourceId
/// </summary>
public int SourceId { get; set; } /// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; }
}
}

剩下的大家自己完成,最终数据库生成一张空的数据表,meowv_hotnews 。

然后还是将我们各大平台放到一个枚举类HotNewsEnum.cs中。

//HotNewsEnum.cs
using System.ComponentModel; namespace Meowv.Blog.Domain.Shared.Enum
{
public enum HotNewsEnum
{
[Description("博客园")]
cnblogs = 1, [Description("V2EX")]
v2ex = 2, [Description("SegmentFault")]
segmentfault = 3, [Description("掘金")]
juejin = 4, [Description("微信热门")]
weixin = 5, [Description("豆瓣精选")]
douban = 6, [Description("IT之家")]
ithome = 7, [Description("36氪")]
kr36 = 8, [Description("百度贴吧")]
tieba = 9, [Description("百度热搜")]
baidu = 10, [Description("微博热搜")]
weibo = 11, [Description("知乎热榜")]
zhihu = 12, [Description("知乎日报")]
zhihudaily = 13, [Description("网易新闻")]
news163 = 14, [Description("GitHub")]
github = 15, [Description("抖音热点")]
douyin_hot = 16, [Description("抖音视频")]
douyin_video = 17, [Description("抖音正能量")]
douyin_positive = 18
}
}

和上一篇抓取壁纸一样,做一些准备工作。

.Application.Contracts层添加HotNewsJobItem<T>,在.BackgroundJobs层添加HotNewsJob用来处理爬虫逻辑,用构造函数方式注入仓储IHotNewsRepository

//HotNewsJobItem.cs
using Meowv.Blog.Domain.Shared.Enum; namespace Meowv.Blog.Application.Contracts.HotNews
{
public class HotNewsJobItem<T>
{
/// <summary>
/// <see cref="Result"/>
/// </summary>
public T Result { get; set; } /// <summary>
/// 来源
/// </summary>
public HotNewsEnum Source { get; set; }
}
}
//HotNewsJob.CS
using Meowv.Blog.Domain.HotNews.Repositories;
using System;
using System.Net.Http;
using System.Threading.Tasks; namespace Meowv.Blog.BackgroundJobs.Jobs.HotNews
{
public class HotNewsJob : IBackgroundJob
{
private readonly IHttpClientFactory _httpClient;
private readonly IHotNewsRepository _hotNewsRepository; public HotNewsJob(IHttpClientFactory httpClient,
IHotNewsRepository hotNewsRepository)
{
_httpClient = httpClient;
_hotNewsRepository = hotNewsRepository;
} public async Task ExecuteAsync()
{
throw new NotImplementedException();
}
}
}

接下来明确数据源地址,因为以上数据源有的返回是HTML,有的直接返回JSON数据。为了方便调用,我这里还注入了IHttpClientFactory

整理好的待抓取数据源列表是这样的。

...
var hotnewsUrls = new List<HotNewsJobItem<string>>
{
new HotNewsJobItem<string> { Result = "https://www.cnblogs.com", Source = HotNewsEnum.cnblogs },
new HotNewsJobItem<string> { Result = "https://www.v2ex.com/?tab=hot", Source = HotNewsEnum.v2ex },
new HotNewsJobItem<string> { Result = "https://segmentfault.com/hottest", Source = HotNewsEnum.segmentfault },
new HotNewsJobItem<string> { Result = "https://web-api.juejin.im/query", Source = HotNewsEnum.juejin },
new HotNewsJobItem<string> { Result = "https://weixin.sogou.com", Source = HotNewsEnum.weixin },
new HotNewsJobItem<string> { Result = "https://www.douban.com/group/explore", Source = HotNewsEnum.douban },
new HotNewsJobItem<string> { Result = "https://www.ithome.com", Source = HotNewsEnum.ithome },
new HotNewsJobItem<string> { Result = "https://36kr.com/newsflashes", Source = HotNewsEnum.kr36 },
new HotNewsJobItem<string> { Result = "http://tieba.baidu.com/hottopic/browse/topicList", Source = HotNewsEnum.tieba },
new HotNewsJobItem<string> { Result = "http://top.baidu.com/buzz?b=341", Source = HotNewsEnum.baidu },
new HotNewsJobItem<string> { Result = "https://s.weibo.com/top/summary/summary", Source = HotNewsEnum.weibo },
new HotNewsJobItem<string> { Result = "https://www.zhihu.com/api/v3/feed/topstory/hot-lists/total?limit=50&desktop=true", Source = HotNewsEnum.zhihu },
new HotNewsJobItem<string> { Result = "https://daily.zhihu.com", Source = HotNewsEnum.zhihudaily },
new HotNewsJobItem<string> { Result = "http://news.163.com/special/0001386F/rank_whole.html", Source = HotNewsEnum.news163 },
new HotNewsJobItem<string> { Result = "https://github.com/trending", Source = HotNewsEnum.github },
new HotNewsJobItem<string> { Result = "https://www.iesdouyin.com/web/api/v2/hotsearch/billboard/word", Source = HotNewsEnum.douyin_hot },
new HotNewsJobItem<string> { Result = "https://www.iesdouyin.com/web/api/v2/hotsearch/billboard/aweme", Source = HotNewsEnum.douyin_video },
new HotNewsJobItem<string> { Result = "https://www.iesdouyin.com/web/api/v2/hotsearch/billboard/aweme/?type=positive", Source = HotNewsEnum.douyin_positive },
};
...

其中有几个比较特殊的,掘金、百度热搜、网易新闻。

掘金需要发送Post请求,返回的是JSON数据,并且需要指定特有的请求头和请求数据,所有使用IHttpClientFactory创建了HttpClient对象。

百度热搜、网易新闻两个老大哥玩套路,网页编码是GB2312的,所以要专门为其指定编码方式,不然取到的数据都是乱码。

...
var web = new HtmlWeb();
var list_task = new List<Task<HotNewsJobItem<object>>>(); hotnewsUrls.ForEach(item =>
{
var task = Task.Run(async () =>
{
var obj = new object(); if (item.Source == HotNewsEnum.juejin)
{
using var client = _httpClient.CreateClient();
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.14 Safari/537.36 Edg/83.0.478.13");
client.DefaultRequestHeaders.Add("X-Agent", "Juejin/Web");
var data = "{\"extensions\":{\"query\":{ \"id\":\"21207e9ddb1de777adeaca7a2fb38030\"}},\"operationName\":\"\",\"query\":\"\",\"variables\":{ \"first\":20,\"after\":\"\",\"order\":\"THREE_DAYS_HOTTEST\"}}";
var buffer = data.SerializeUtf8();
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var httpResponse = await client.PostAsync(item.Result, byteContent);
obj = await httpResponse.Content.ReadAsStringAsync();
}
else
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
obj = await web.LoadFromWebAsync(item.Result, (item.Source == HotNewsEnum.baidu || item.Source == HotNewsEnum.news163) ? Encoding.GetEncoding("GB2312") : Encoding.UTF8);
} return new HotNewsJobItem<object>
{
Result = obj,
Source = item.Source
};
});
list_task.Add(task);
});
Task.WaitAll(list_task.ToArray());

循环 hotnewsUrls ,可以看到HotNewsJobItem我们返回的是object类型,因为有JSON又有HtmlDocument对象。所以这里为了能够统一接收,就是用了object。

针对掘金做了单独处理,使用HttpClient发送Post请求,返回JSON字符串数据。

针对百度热搜和网易新闻,使用Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);注册编码提供程序,然后在web.LoadFromWebAsync(...)加载网页数据的时候指定网页编码,我使用了一个三元表达式来处理。

完成上面这一步,就可以循环 list_task,使用XPath语法,或者解析JSON数据,去拿到数据了。

...
var hotNews = new List<HotNews>();
foreach (var list in list_task)
{
var item = await list;
var sourceId = (int)item.Source; ... if (hotNews.Any())
{
await _hotNewsRepository.DeleteAsync(x => true);
await _hotNewsRepository.BulkInsertAsync(hotNews);
}
}

这个爬虫同样很简单,只要拿到标题和链接即可,所以主要目标是寻找到页面上的a标签列表。这个我觉得也没必要一个个去分析了,直接上代码。

// 博客园
if (item.Source == HotNewsEnum.cnblogs)
{
var nodes = ((HtmlDocument)item.Result).DocumentNode.SelectNodes("//div[@class='post_item_body']/h3/a").ToList();
nodes.ForEach(x =>
{
hotNews.Add(new HotNews
{
Title = x.InnerText,
Url = x.GetAttributeValue("href", ""),
SourceId = sourceId,
CreateTime = DateTime.Now
});
});
}
// V2EX
if (item.Source == HotNewsEnum.v2ex)
{
var nodes = ((HtmlDocument)item.Result).DocumentNode.SelectNodes("//span[@class='item_title']/a").ToList();
nodes.ForEach(x =>
{
hotNews.Add(new HotNews
{
Title = x.InnerText,
Url = $"https://www.v2ex.com{x.GetAttributeValue("href", "")}",
SourceId = sourceId,
CreateTime = DateTime.Now
});
});
}
 // SegmentFault
if (item.Source == HotNewsEnum.segmentfault)
{
var nodes = ((HtmlDocument)item.Result).DocumentNode.SelectNodes("//div[@class='news__item-info clearfix']/a").Where(x => x.InnerText.IsNotNullOrEmpty()).ToList();
nodes.ForEach(x =>
{
hotNews.Add(new HotNews
{
Title = x.SelectSingleNode(".//h4").InnerText,
Url = $"https://segmentfault.com{x.GetAttributeValue("href", "")}",
SourceId = sourceId,
CreateTime = DateTime.Now
});
});
}
// 掘金
if (item.Source == HotNewsEnum.juejin)
{
var obj = JObject.Parse((string)item.Result);
var nodes = obj["data"]["articleFeed"]["items"]["edges"];
foreach (var node in nodes)
{
hotNews.Add(new HotNews
{
Title = node["node"]["title"].ToString(),
Url = node["node"]["originalUrl"].ToString(),
SourceId = sourceId,
CreateTime = DateTime.Now
});
}
}
// 微信热门
if (item.Source == HotNewsEnum.weixin)
{
var nodes = ((HtmlDocument)item.Result).DocumentNode.SelectNodes("//ul[@class='news-list']/li/div[@class='txt-box']/h3/a").ToList();
nodes.ForEach(x =>
{
hotNews.Add(new HotNews
{
Title = x.InnerText,
Url = x.GetAttributeValue("href", ""),
SourceId = sourceId,
CreateTime = DateTime.Now
});
});
}
// 豆瓣精选
if (item.Source == HotNewsEnum.douban)
{
var nodes = ((HtmlDocument)item.Result).DocumentNode.SelectNodes("//div[@class='channel-item']/div[@class='bd']/h3/a").ToList();
nodes.ForEach(x =>
{
hotNews.Add(new HotNews
{
Title = x.InnerText,
Url = x.GetAttributeValue("href", ""),
SourceId = sourceId,
CreateTime = DateTime.Now
});
});
}
// IT之家
if (item.Source == HotNewsEnum.ithome)
{
var nodes = ((HtmlDocument)item.Result).DocumentNode.SelectNodes("//div[@class='lst lst-2 hot-list']/div[1]/ul/li/a").ToList();
nodes.ForEach(x =>
{
hotNews.Add(new HotNews
{
Title = x.InnerText,
Url = x.GetAttributeValue("href", ""),
SourceId = sourceId,
CreateTime = DateTime.Now
});
});
}
// 36氪
if (item.Source == HotNewsEnum.kr36)
{
var nodes = ((HtmlDocument)item.Result).DocumentNode.SelectNodes("//div[@class='hotlist-main']/div[@class='hotlist-item-toptwo']/a[2]|//div[@class='hotlist-main']/div[@class='hotlist-item-other clearfloat']/div[@class='hotlist-item-other-info']/a").ToList();
nodes.ForEach(x =>
{
hotNews.Add(new HotNews
{
Title = x.InnerText,
Url = $"https://36kr.com{x.GetAttributeValue("href", "")}",
SourceId = sourceId,
CreateTime = DateTime.Now
});
});
}
// 百度贴吧
if (item.Source == HotNewsEnum.tieba)
{
var obj = JObject.Parse(((HtmlDocument)item.Result).ParsedText);
var nodes = obj["data"]["bang_topic"]["topic_list"];
foreach (var node in nodes)
{
hotNews.Add(new HotNews
{
Title = node["topic_name"].ToString(),
Url = node["topic_url"].ToString().Replace("amp;", ""),
SourceId = sourceId,
CreateTime = DateTime.Now
});
}
}
// 百度热搜
if (item.Source == HotNewsEnum.baidu)
{
var nodes = ((HtmlDocument)item.Result).DocumentNode.SelectNodes("//table[@class='list-table']//tr/td[@class='keyword']/a[@class='list-title']").ToList();
nodes.ForEach(x =>
{
hotNews.Add(new HotNews
{
Title = x.InnerText,
Url = x.GetAttributeValue("href", ""),
SourceId = sourceId,
CreateTime = DateTime.Now
});
});
}
// 微博热搜
if (item.Source == HotNewsEnum.weibo)
{
var nodes = ((HtmlDocument)item.Result).DocumentNode.SelectNodes("//table/tbody/tr/td[2]/a").ToList();
nodes.ForEach(x =>
{
hotNews.Add(new HotNews
{
Title = x.InnerText,
Url = $"https://s.weibo.com{x.GetAttributeValue("href", "").Replace("#", "%23")}",
SourceId = sourceId,
CreateTime = DateTime.Now
});
});
}
// 知乎热榜
if (item.Source == HotNewsEnum.zhihu)
{
var obj = JObject.Parse(((HtmlDocument)item.Result).ParsedText);
var nodes = obj["data"];
foreach (var node in nodes)
{
hotNews.Add(new HotNews
{
Title = node["target"]["title"].ToString(),
Url = $"https://www.zhihu.com/question/{node["target"]["id"]}",
SourceId = sourceId,
CreateTime = DateTime.Now
});
}
}
// 知乎日报
if (item.Source == HotNewsEnum.zhihudaily)
{
var nodes = ((HtmlDocument)item.Result).DocumentNode.SelectNodes("//div[@class='box']/a").ToList();
nodes.ForEach(x =>
{
hotNews.Add(new HotNews
{
Title = x.InnerText,
Url = $"https://daily.zhihu.com{x.GetAttributeValue("href", "")}",
SourceId = sourceId,
CreateTime = DateTime.Now
});
});
}
// 网易新闻
if (item.Source == HotNewsEnum.news163)
{
var nodes = ((HtmlDocument)item.Result).DocumentNode.SelectNodes("//div[@class='area-half left']/div[@class='tabBox']/div[@class='tabContents active']/table//tr/td[1]/a").ToList();
nodes.ForEach(x =>
{
hotNews.Add(new HotNews
{
Title = x.InnerText,
Url = x.GetAttributeValue("href", ""),
SourceId = sourceId,
CreateTime = DateTime.Now
});
});
}
// GitHub
if (item.Source == HotNewsEnum.github)
{
var nodes = ((HtmlDocument)item.Result).DocumentNode.SelectNodes("//article[@class='Box-row']/h1/a").ToList();
nodes.ForEach(x =>
{
hotNews.Add(new HotNews
{
Title = x.InnerText.Trim().Replace("\n", "").Replace(" ", ""),
Url = $"https://github.com{x.GetAttributeValue("href", "")}",
SourceId = sourceId,
CreateTime = DateTime.Now
});
});
}
// 抖音热点
if (item.Source == HotNewsEnum.douyin_hot)
{
var obj = JObject.Parse(((HtmlDocument)item.Result).ParsedText);
var nodes = obj["word_list"];
foreach (var node in nodes)
{
hotNews.Add(new HotNews
{
Title = node["word"].ToString(),
Url = $"#{node["hot_value"]}",
SourceId = sourceId,
CreateTime = DateTime.Now
});
}
}
// 抖音视频 & 抖音正能量
if (item.Source == HotNewsEnum.douyin_video || item.Source == HotNewsEnum.douyin_positive)
{
var obj = JObject.Parse(((HtmlDocument)item.Result).ParsedText);
var nodes = obj["aweme_list"];
foreach (var node in nodes)
{
hotNews.Add(new HotNews
{
Title = node["aweme_info"]["desc"].ToString(),
Url = node["aweme_info"]["share_url"].ToString(),
SourceId = sourceId,
CreateTime = DateTime.Now
});
}
}

item.Result转换成指定类型,最终拿到数据后,我们先删除所有数据后再批量插入。

然后新建扩展方法UseHotNewsJob(),在模块类中调用。

//MeowvBlogBackgroundJobsExtensions.cs
...
/// <summary>
/// 每日热点数据抓取
/// </summary>
/// <param name="context"></param>
public static void UseHotNewsJob(this IServiceProvider service)
{
var job = service.GetService<HotNewsJob>(); RecurringJob.AddOrUpdate("每日热点数据抓取", () => job.ExecuteAsync(), CronType.Hour(1, 2));
}
...

指定定时任务为每2小时运行一次。

...
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
...
var service = context.ServiceProvider;
...
service.UseHotNewsJob();
}

编译运行,此时周期性作业就会出现我们的定时任务了。

默认时间没到是不会执行的,我们手动执行等待一会看看效果。

执行完成后,成功将所有热点数据保存在数据库中,说明我们的爬虫已经搞定了,并且Hangfire会按照给定的规则去循环执行,你学会了吗?

开源地址:https://github.com/Meowv/Blog/tree/blog_tutorial

基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(二)的更多相关文章

  1. 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(三)

    上一篇(https://www.cnblogs.com/meowv/p/12974439.html)完成了全网各大平台的热点新闻数据的抓取,本篇继续围绕抓取完成后的操作做一个提醒.当每次抓取完数据后, ...

  2. 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(一)

    上一篇(https://www.cnblogs.com/meowv/p/12966092.html)文章使用AutoMapper来处理对象与对象之间的映射关系,本篇主要围绕定时任务和数据抓取相关的知识 ...

  3. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(一)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  4. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(二)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  5. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(三)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  6. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(四)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  7. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(五)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  8. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(一)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  9. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(二)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

随机推荐

  1. 惠普 HP Pavilion 15 Notebook PC清灰教程总结 惠普g4系列清灰加内存条教程

    最近天气热的电脑都受不了,风扇总是异响,声音很大,感觉是散热不行了,就把电脑清一下灰,虽然之前也清过,但是基本都忘记了,机子比较老,找不到具体教程,清灰过程中因为不熟悉有点费劲,手动记录一下,方便下次 ...

  2. MongoDB 部署以及操作

    目录 1.MongoDB简介 2.MongoDB优势 3.MongoDB安装 3.MongoDB用户管理 3.1.Mongodb创建超级管理员 3.2.MongoDB创建读写用户 3.3.Moongo ...

  3. D. Count the Arrays 计数题

    D. Count the Arrays 也是一个计数题. 题目大意: 要求构造一个满足题意的数列. \(n\) 代表数列的长度 数列元素的范围 \([1,m]\) 数列必须有且仅有一对相同的数 存在一 ...

  4. B - Planning 早训 贪心

    B - Planning 这个题目我知道要贪心,也知道怎么贪,但是写不出来,感觉自己好菜. 这个题目要用优先队列维护. 题目大意是飞机延误,不同的飞机每次延误一分钟,它的代价不同,然后问,怎么安排才能 ...

  5. M - Little Pony and Harmony Chest 状压dp

    M - Little Pony and Harmony Chest 怎么感觉自己越来越傻了,都知道状态的定义了还没有推出转移方程. 首先这个a的范围是0~30   这里可以推出 b数组的范围 0~60 ...

  6. (一)Redis介绍

    1 背景 在早期的互联网Web 1.0时代,大部分企业还是采用传统的企业级单体应用架构,而一时间蜂拥而至的巨大用户流量使得这种架构难以支撑,通过对诸多系统架构实施以及对巨大用户流量的分析过程中发现,其 ...

  7. SAP ME31K SUBOBJECT_NOT_FOUND

    SUBOBJECT_NOT_FOUND 在使用BAPI:BAPI_CONTRACT_CREATE创建协议时报错, 错误位置在此处,子对象没找到 GOOGLE到相关解决方案 事务代码:SLG0 新增对象 ...

  8. git --添加多个文件

    今天测试,发现之前写的auto testcase,有好多发生了改变,因此需要修改脚本重新上传至git当中. 对好几个test case script 进行了修改,之前只是一个一个的修改,这次是多个,经 ...

  9. 关于Tomcat+Nginx负载均衡与Jmeter服务器测压的日记

    Jmeter测压 1.Jmeter-5.1.1下载:http://mirror.bit.edu.cn/apache//jmeter/binaries/apache-jmeter-5.1.1.zip 2 ...

  10. React实践:自定义html特性不显示

    发现React中自定义的html特性在render后是不现实,而且getAttribute方法也只能获取到undefined. 后来去stackoverflow提问,网友回答说: It depends ...