网页PDF链接爬取失败求助(F#实现)
问题分析
你当前的代码无法获取PDF链接,核心原因是这些链接并非服务器直接返回的静态HTML内容,而是页面加载后通过JavaScript动态生成的。FSharp.Data、HtmlAgilityPack这类工具只能抓取服务器返回的原始HTML源码,无法执行页面中的JavaScript,自然看不到动态渲染出来的PDF链接,和反爬机制无关。
解决方案
针对动态渲染的页面,有两种常见的解决思路:
1. 使用浏览器自动化工具(模拟真实浏览器渲染)
这类工具可以模拟真实浏览器的行为,加载页面并执行所有JavaScript,然后获取渲染完成后的完整HTML。推荐使用Playwright for .NET,它支持F#,且操作简单。
实现步骤:
- 先安装Playwright的NuGet包:
Microsoft.Playwright - 编写F#代码:
open Microsoft.Playwright open System [<EntryPoint>] let main argv = async { use! playwright = Playwright.CreateAsync() use! browser = playwright.Chromium.LaunchAsync(LaunchOptions(Headless = true)) use! page = browser.NewPageAsync() do! page.GotoAsync("https://www.kodis.cz/lines/region?tab=232-293") // 等待PDF链接所在元素加载完成 do! page.WaitForSelectorAsync("a[href*='kodis-files.s3']") |> Async.AwaitTask // 提取所有PDF链接 let! pdfLinks = page.QuerySelectorAllAsync("a[href*='kodis-files.s3']") |> Async.AwaitTask for link in pdfLinks do let! href = link.GetAttributeAsync("href") |> Async.AwaitTask printfn "%s" href } |> Async.RunSynchronously 0
2. 直接调用后端API获取数据
大部分动态渲染的页面,数据都是通过AJAX请求从后端API获取的。你可以通过浏览器开发者工具找到对应的API接口,直接请求接口获取包含PDF链接的JSON数据,这种方式效率比浏览器自动化更高。
操作步骤:
- 打开目标页面,按下F12打开开发者工具,切换到「Network」标签
- 刷新页面,筛选「XHR/Fetch」类型的请求,找到返回PDF相关数据的API(通常返回JSON格式)
- 复制该API的请求URL、必要的请求头,然后用F#的HTTP工具(比如
FSharp.Data.Http)直接请求并解析JSON
示例代码(假设找到的API为https://www.kodis.cz/api/lines/232-293):
open FSharp.Data type LineData = JsonProvider<"""{ "pdfLinks": ["https://kodis-files.s3...pdf"] }"""> let apiUrl = "https://www.kodis.cz/api/lines/232-293" let response = Http.RequestString(apiUrl) let data = LineData.Parse(response) data.PdfLinks |> List.iter (printfn "%s")
附:你提供的代码与页面结构
你的F#代码
//******************************************* let url0 = "https://www.kodis.cz/lines/region?tab=232-293" let document0 = HtmlDocument.Load(url0) document0.CssSelect("div#__next") |> List.iter (fun item -> let querySelector (tag: string) = (item.Descendants tag) (querySelector "a") |> Seq.iter (fun item -> let url = item.AttributeValue "href" printfn "%s" url ) ) //******************************************* let url = "https://www.kodis.cz/lines/region?tab=232-293" let document = HtmlDocument.Load(url) let links = document.Descendants "a" |> Seq.choose (fun x -> x.TryGetAttribute("href") |> Option.map (fun a -> x.InnerText(), a.Value()) ) |> Seq.toList printfn "%A" links
页面相关HTML结构
<div id="__next" data-reactroot=""> <!-- many "a hrefs" with links to various stuff --> <main class="mt-16"> <div class="container"> <div class="mb-12"> <ul class="mb-8 grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-2"> <li class="Card_wrapper__ZQ5Fp"> <div class="Card_actions__HhB_f"> <a href="https://kodis-files.s3.eu-central-1.amazonaws.com/232_2022_12_11_2023_12_09_d02eef94bc.pdf" target="_blank" class="Button_main__pEB6O Button_secondary__R6QEg Button_md__1RLR1" data-testid="button-elementAnchor" title="Pravidelný jízdní řád"> </a> </div> </li> <li class="Card_wrapper__ZQ5Fp"> <!-- another "a href" with a link to a pdf file --> </li> <li class="Card_wrapper__ZQ5Fp"> <!-- another "a href" with a link to a pdf file --> </li> </ul> </div> </div> </main> </div>
内容的提问来源于stack exchange,提问作者Miroslav Husťák
相关产品推荐
相关产品推荐

