从网页中提取数据,解析特定部分,然后显示数据

Pulling data from a webpage, parsing it for specific pieces, and displaying it

提问人:Aloehart 提问时间:8/6/2013 最后编辑:Aloehart 更新时间:2/14/2021 访问量:104586

问:

我已经使用这个网站很长时间来寻找问题的答案,但我无法找到这个问题的答案。

我正在与一个小组一起完成一个班级项目。我们将建立一个小型的“游戏交易”网站,允许人们注册,放入他们想要交易的游戏,并接受他人的交易或请求交易。

我们让网站提前很久运行,因此我们正试图向网站添加更多内容。我自己想做的一件事是将放入 Metacritic 的游戏联系起来。

这是我需要做的。我需要(在 Visual Studio 2012 中使用 asp 和 c#)在 metacritic 上获取正确的游戏页面,提取其数据,解析特定部分,然后在我们的页面上显示数据。

从本质上讲,当您选择要交易的游戏时,我们希望显示一个小的div,其中包含游戏的信息和评级。我想以这种方式来学习更多,并从这个项目中得到一些东西,我不必开始。

我想知道是否有人可以告诉我从哪里开始。我不知道如何从页面中提取数据。我仍在试图弄清楚我是否需要尝试写一些东西来自动搜索游戏的标题并以这种方式找到页面,或者我是否可以找到某种直接进入游戏页面的方法。一旦我拿到数据,我就不知道如何从中提取我需要的具体信息。

让这变得不容易的一件事是,我正在学习 c++ 以及 c# 和 asp,所以我一直在交叉我的电线。如果有人能为我指出正确的方向,那将是一个很大的帮助。谢谢

C# asp.net 解析 Web 爬虫 服务器端

评论

1赞 ryan 8/6/2013
Google、HTML Agility Pack 和 Fiddler
1赞 Greg 8/6/2013
您要查找的术语是屏幕抓取或网页抓取

答:

55赞 Hanlet Escaño 8/6/2013 #1

这个小示例使用 HtmlAgilityPack,并使用选择器来获取所需的元素。XPath

protected void Page_Load(object sender, EventArgs e)
{
    string url = "http://www.metacritic.com/game/pc/halo-spartan-assault";
    var web = new HtmlAgilityPack.HtmlWeb();
    HtmlDocument doc = web.Load(url);

    string metascore = doc.DocumentNode.SelectNodes("//*[@id=\"main\"]/div[3]/div/div[2]/div[1]/div[1]/div/div/div[2]/a/span[1]")[0].InnerText;
    string userscore = doc.DocumentNode.SelectNodes("//*[@id=\"main\"]/div[3]/div/div[2]/div[1]/div[2]/div[1]/div/div[2]/a/span[1]")[0].InnerText;
    string summary = doc.DocumentNode.SelectNodes("//*[@id=\"main\"]/div[3]/div/div[2]/div[2]/div[1]/ul/li/span[2]/span/span[1]")[0].InnerText;
}

获取给定元素的一种简单方法是使用您的 Web 浏览器(我使用 Chrome)开发人员工具:XPath

  • 打开开发人员工具(在 Windows 上为 + +,在 Mac 上为 + +)。F12CtrlShiftCCommandShiftC
  • 在页面中选择要为其使用 XPath 的元素。
  • 右键单击“元素”选项卡中的元素。
  • 单击“复制为 XPath”。

您可以像在 c# 中一样粘贴它(如我的代码所示),但请确保对引号进行转义。

您必须确保使用一些错误处理技术,因为如果 Web 抓取更改页面的 HTML 格式,可能会导致错误。

编辑

根据 @knocte 的建议,下面是指向 HTMLAgilityPack 的 Nuget 包的链接:

https://www.nuget.org/packages/HtmlAgilityPack/

评论

3赞 Aloehart 9/13/2013
我花了一段时间才意识到我的浏览器拉取 xpath 的方式与 html 敏捷包使用的不同,但是一旦我弄清楚了这个问题,我只花了几个小时就得到了我想做的事情的正常设置。谢谢你的帮助。
0赞 Djeroen 11/5/2015
@Aloehart HTML Agility Pack 如何想要 XPaths?我想我也有同样的问题
5赞 cheesey_toastie 2/25/2016
请注意 - Chrome“修复”html。假设您查询表中的元素,如果源 html 没有正确的 <tbody> 部分,Chrome 将添加它以呈现页面并在 xpath 中返回。对于您的代码,您不需要路径的 tbody 部分。要检查、查看页面的来源并感知,请检查您的 xpath。
1赞 Tomi 12/15/2017
我更喜欢使用 CSS 选择器,然后使用 Dcsoup。stackoverflow.com/a/33756899/4080226
1赞 knocte 7/5/2019
如何更新此答案以提及 NuGet 包?nuget.org/packages/HtmlAgilityPack
10赞 JeremiahDotNet 8/6/2013 #2

我看了看,Metacritic.com 没有 API。

可以使用 HttpWebRequest 以字符串形式获取网站的内容。

using System.Net;
using System.IO;
using System.Windows.Forms;

string result = null;
string url = "http://www.stackoverflow.com";
WebResponse response = null;
StreamReader reader = null;

try
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "GET";
    response = request.GetResponse();
    reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
    result = reader.ReadToEnd();
}
catch (Exception ex)
{
    // handle error
    MessageBox.Show(ex.Message);
}
finally
{
    if (reader != null)
        reader.Close();
    if (response != null)
        response.Close();
}

然后,您可以利用 Metacritic 对元标记的使用来解析所需数据的字符串。以下是他们在元标记中提供的信息:

  • og:标题
  • og:类型
  • og:网址
  • og:图像
  • og:site_name
  • og:描述

每个标签的格式为:meta name="og:title" content="In a World..."

评论

0赞 FistOfFury 11/13/2018
这是最好的答案,因为它将实际的“抓取”(从站点获取 HTML)与解析分开。解析 HTML 可以在单独的过程中完成。
10赞 Jason Goemaat 11/17/2015 #3

我推荐Dcsoup。它有一个 nuget 包,它使用 CSS 选择器,所以如果你使用 jquery,它会很熟悉。我尝试过其他方法,但它是我发现的最好和最容易使用的。没有太多的文档,但它是开源的,并且是 java jsoup 库的端口,有很好的文档。(此处提供了 .NET API 的文档。我非常喜欢它。

var timeoutInMilliseconds = 5000;
var uri = new Uri("http://www.metacritic.com/game/pc/fallout-4");
var doc = Supremes.Dcsoup.Parse(uri, timeoutInMilliseconds);

// <span itemprop="ratingValue">86</span>
var ratingSpan = doc.Select("span[itemprop=ratingValue]");
int ratingValue = int.Parse(ratingSpan.Text);

// selectors match both critic and user scores
var scoreDiv = doc.Select("div.score_summary");
var scoreAnchor = scoreDiv.Select("a.metascore_anchor");
int criticRating = int.Parse(scoreAnchor[0].Text);
float userRating = float.Parse(scoreAnchor[1].Text);

评论

0赞 Jose A 11/4/2016
棒!多谢。我想知道为什么它没有在线文档......那样会很光滑!
0赞 oneManArmin 7/13/2017
这正是我需要的。然而,奇怪的是,这为我带来了与文化相关的问题:当我尝试使用具有分数的 HTML 文本元素(例如,7.5)时,我遇到了解析错误,因为我的文化设置不同(例如,7.5 是 7,5)。因此,每当我使用分数解析时,我都必须从命名空间中包含作为可选参数,然后它就可以正常工作了。float.Parse()CultureInfo.InvariantCultureSystem.Globalization
0赞 knocte 7/5/2019
一直在尝试复杂的选择器,例如 OR,但它们似乎不起作用:(table:nth-child(1) tr:nth-child(1) td:nth-child(1)table:nth-child(1)>tbody>tr:nth-child(1)>td:nth-child(1)
1赞 jasniec 11/2/2019 #4

我向你推荐 WebsiteParser - 它基于 HtmlAgilityPack(Hanlet Escaño 提到),但它通过属性和 css 选择器使 Web 抓取更容易:

class PersonModel
{
    [Selector("#BirdthDate")]
    [Converter(typeof(DateTimeConverter))]
    public DateTime BirdthDate { get; set; }
}

// ...

PersonModel person = WebContentParser.Parse<PersonModel>(html);

Nuget 链接