目录
- 一. 需求
- 二. 分析
- 2.1 思路分析
- 2.2 技术点
- 三. 代码
- 四. 效果
一. 需求
⏹有网站如下所示,先要求从按照关键词搜索到的网页中,提取出所有的磁力链接。
二. 分析
2.1 思路分析
- 打开网页之后,从网页中先提取出所有的标题相关的url
- 然后再打开所有提取到的url
- 再从每一个新打开的页面中获取磁力链接所在a标签的href属性值
2.2 技术点
Invoke-WebRequest
:发送网络请求workflow
- workflow 是一种特殊的语法结构,用于创建并发执行的工作流。工作流允许你定义一系列步骤,这些步骤可以同时执行或并行执行,适用于需要处理大量数据或需要在多个计算资源上执行任务的情况。
- 在 foreach -parallel 循环内并行执行多个任务,从而加快处理速度。
InlineScript { ... }
:内联脚本块用于在工作流中执行本地 PowerShell 脚本或命令。
Add-Type -Path ".\xxx.dll"
:用于引入第三方dllNew-Object HtmlAgilityPack.HtmlDocument
:用于创建引入的库中的对象HtmlAgilityPack
:用于解析html文本的第三方库- 官网:https://github.com/zzzprojects/html-agility-pack/releases/tag/v1.11.61
- 下载源码后,手动编译 HtmlAgilityPack.Net40,得到 HtmlAgilityPack.dll
.DocumentNode.SelectSingleNode
:用于配合XPATH语法解析html文本[System.Uri]::EscapeDataString($搜索关键词)
- 搜索的关键字是中文,实际发送请求时,需要把中文转换
三. 代码
param(
# 参数必须输入
[Parameter(Mandatory)]
# 当未添加 -name 参数时,脚本会报错
[string]$搜索关键词
)
# 域名
$domain = 'http://www.kisssub.org'
# 搜索关键字,通过 [System.Uri]::EscapeDataString 对汉字进行编码
$enCoded_search_keyword = [System.Uri]::EscapeDataString($搜索关键词)
# 请求地址
$request_url = "$($domain)/search.php?keyword=$($enCoded_search_keyword)"
# session
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$session.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36"
$session.Cookies.Add((New-Object System.Net.Cookie("user_script_url", "%2F%2F1.acgscript.com%2Fscript%2Fmiobt%2F4.js%3F3", "/", "www.kisssub.org")))
$session.Cookies.Add((New-Object System.Net.Cookie("user_script_rev", "20181120.2", "/", "www.kisssub.org")))
# 请求头
$request_header = @{
"Accept"="text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
"Accept-Encoding"="gzip, deflate"
"Accept-Language"="zh-CN,zh;q=0.9,ja;q=0.8,en;q=0.7,zh-TW;q=0.6"
"Cache-Control"="no-cache"
"Pragma"="no-cache"
"Upgrade-Insecure-Requests"="1"
}
# 获取磁力链接所在页面的URL
function Get_WEB_URL {
param (
[string]$url
, [Microsoft.PowerShell.Commands.WebRequestSession]$session
, [PSCustomObject]$header
)
# 发送网络请求
$response = Invoke-WebRequest -UseBasicParsing `
-Uri $url `
-WebSession $session `
-Headers $header
# 若响应code不是200,则证明网络连接失败
if ($response.StatusCode -ne 200) {
Write-Host "网络请求失败..."
return
}
# 提取磁力链接所在页面的url
$target_web_urls = $response.Links.outerHTML | ForEach-Object {
# 若不是对应页面的url,则跳过
if (-not ($_ -match ".*show.*.html")) {
return
}
# 提取出目标页面的url
$_.split(" ")[1].replace("href=`"", "$($domain)/").replace("`"", "")
}
return $target_web_urls
}
# 指定url,session,header 发送网络请求
$target_web_urls = Get_WEB_URL -url $request_url -session $session -header $request_header
$target_web_urls | Out-Host
<#
⏹创建一个workflow,用于并发处理多任务
#>
workflow Get-WebContent {
param (
[string[]] $urls
)
<#
⏹foreach -parallel 是 Workflow 中用来并行处理迭代集合的语法
每个 $url 都会并行处理,即同时发送多个请求以提高效率
#>
foreach -parallel ($url in $urls) {
# 睡眠1秒
# Start-Sleep -Seconds 1
# ⏹InlineScript 块允许在 Workflow 中执行本地的 PowerShell 脚本或命令
$web_response = InlineScript {
# 发送网络请求
$webRequest = Invoke-WebRequest -UseBasicParsing -Uri $using:url -Headers $my_header
# 获取页面上的所有url连接
$webRequest.Links.outerHTML
}
# PSCustomObject 是自定义对象的数据类型
[PSCustomObject]@{
Content = $web_response
}
}
}
Write-Host "⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓提取到的磁力链接如下⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓" -ForegroundColor Red
# 引入 HtmlAgilityPack.dll 依赖库
Add-Type -Path ".\HtmlAgilityPack.dll"
# 创建 HtmlDocument对象 用于解析html文本
$htmlDoc = New-Object HtmlAgilityPack.HtmlDocument
# 调用workflow,获取响应
$results = Get-WebContent -urls $target_web_urls
$results.Content | ForEach-Object {
# 如果不是磁力链接的url,就跳过
if (-not ($_ -match ".*ref=`"magnet.*")) {
return
}
# 将含有磁力链接的html文本放到 HtmlDocument对象 中
$htmlDoc.LoadHtml($_)
<#
⏹通过xpath语法提取到a标签对象
SelectSingleNode
只能提取单节点
SelectNodes
可以提取多个节点
#>
$aEelement = $htmlDoc.DocumentNode.SelectSingleNode("//a[@id='magnet']")
<#
⏹根据id获取href属性(磁力链接内容)
第2个参数是默认参数
#>
$aEelement.GetAttributeValue("href", "")
} | Get-Unique
# 暂停
Pause
四. 效果
- 只是简易爬虫,并未做IP代理池和cookie池等防反扒机制
- 频繁使用,在一段时间内会无法访问该网站