遍历网页并下载 PDF

Iterate through web pages and download PDFs

我有一个代码可以抓取网页上的所有 PDF 文件并将它们下载到文件夹中。但是现在它开始报错:

System.NullReferenceException HResult=0x80004003 Message=Object reference not set to an instance of an object. Source=NW Crawler
StackTrace: at NW_Crawler.Program.Main(String[] args) in C:\Users\PC\source\repos\NW Crawler\NW Crawler\Program.cs:line 16

指向 foreach (HtmlNode src in ProductListPage)

中的 ProductListPage

有没有关于如何解决这个问题的提示?我试图实施 async/await 但没有成功。也许我做错了什么...

这是要完成的过程:

  1. 转到https://www.nordicwater.com/products/waste-water/
  2. 列出部分(相关产品)中的所有 link。他们是:<a class="ap-area-link" href="https://www.nordicwater.com/product/mrs-meva-multi-rake-screen/">MRS MEVA multi rake screen</a>
  3. 继续每个 link 并搜索 PDF 文件。 PDF 文件位于:

                    <div class="dl-items">
    <a href="https://www.nordicwater.com/wp-content/uploads/2016/04/S1126-MRS-brochure-EN.pdf" download="">
    

这是我的完整测试代码:

using HtmlAgilityPack;
using System;
using System.Net;


namespace NW_Crawler
{
    class Program
    {
        static void Main(string[] args)
        {

            {
                HtmlDocument htmlDoc = new HtmlWeb().Load("https://www.nordicwater.com/products/waste-water/");
                HtmlNodeCollection ProductListPage = htmlDoc.DocumentNode.SelectNodes("//a[@class='ap-area-link']//a");
                Console.WriteLine("Here are the links:" + ProductListPage);
                foreach (HtmlNode src in ProductListPage)
                {
                    htmlDoc = new HtmlWeb().Load(src.Attributes["href"].Value);

                    // Thread.Sleep(5000); // wait some time

                    HtmlNodeCollection LinkTester = htmlDoc.DocumentNode.SelectNodes("//div[@class='dl-items']//a");
                    if (LinkTester != null)
                    {
                        foreach (var dllink in LinkTester)
                        {
                            string LinkURL = dllink.Attributes["href"].Value;
                            Console.WriteLine(LinkURL);

                            string ExtractFilename = LinkURL.Substring(LinkURL.LastIndexOf("/"));
                            var DLClient = new WebClient();

                            // Thread.Sleep(5000); // wait some time

                            DLClient.DownloadFileAsync(new Uri(LinkURL), @"C:\temp\" + ExtractFilename);
                        }
                    }
                }
            }

        }
    }
}

您使用的 Xpath 似乎不正确。我尝试在浏览器中加载网页并搜索 xpath 但没有得到任何结果。我将其替换为 //a[@class='ap-area-link'] 并能够找到匹配的元素,如下图所示。

进行了一些更改以弥补您可能看到的错误。

变化

  1. 使用 src.GetAttributeValue("href", string.Empty) 而不是 src.Attribute["href"].Value;。如果 href 不存在或为空,您将得到 Object Reference Not Set to an instance of an object
  2. 检查 ProductListPage 是否有效且不为空。
  3. ExtractFileName 名称中包含一个 /。您想在子字符串方法中使用 + 1 来跳过 'Last / from index of)'.
  4. 如果任一循环中的 href 为空,则继续下一次迭代
  5. 已将产品列表查询从 //a[@class='ap-area-link']//a 更改为 //a[@class='ap-area-link']。您在空的 <a> 标签中搜索 <a>。尽管如此,如果您想以这种方式查询它,第一个检查 ProductListPage != null 是否的 IF 语句将处理错误。
    HtmlDocument htmlDoc = new HtmlWeb().Load("https://www.nordicwater.com/products/waste-water/");
    HtmlNodeCollection ProductListPage = htmlDoc.DocumentNode.SelectNodes("//a[@class='ap-area-link']");
    if (ProductListPage != null)
        foreach (HtmlNode src in ProductListPage)
        {
            string href = src.GetAttributeValue("href", string.Empty);
            if (string.IsNullOrEmpty(href))
                continue;
            htmlDoc = new HtmlWeb().Load(href);
            HtmlNodeCollection LinkTester = htmlDoc.DocumentNode.SelectNodes("//div[@class='dl-items']//a");
            if (LinkTester != null)
                foreach (var dllink in LinkTester)
                {
                    string LinkURL = dllink.GetAttributeValue("href", string.Empty);
                    if (string.IsNullOrEmpty(LinkURL))
                        continue;
                    string ExtractFilename = LinkURL.Substring(LinkURL.LastIndexOf("/") + 1);
                    new WebClient().DownloadFileAsync(new Uri(LinkURL), @"C:\temp\" + ExtractFilename);
                }
        }