缘起
今天查资料的时候,偶然发现了一位国外网友镜像了 TheOleNewThing
从 2003
年到 2019
年的,竟然有 5000
多篇(真是高产)。值得注意的是,微软官方博客中许多链接都已经失效了。为了防止这位网友的镜像链接也失效,我决定赶紧将这些内容下载保存下来。手动保存显然不现实,毕竟有 5000
多篇文章呢!所以,我决定写脚本来自动下载,这才是明智之举!如果是几年前,我肯定要亲自动手写脚本,不过如今,AI
这么强大,我无需再费力。幸运的是,我利用 自动生成下载脚本的全过程,并对其进行了简单的修改,成功地将全部 5000
多篇文章下载并压缩存档,并按年月分类打包好了!不得不赞叹一句,AI
真是太强大了。
下载地址
所有文章已经按年压缩,感兴趣的朋友可以自行下载。
百度云盘: 提取码: dbqt
gitee
:
注: 所有文章版权归原作者所有,我只是为了防止失联,转存一份。侵删!
以下是正文
下载
Q:
download url and save to disk and then parse inner urls and then save these urls to disk
A:
To download a URL, save it to disk, parse inner URLs, and then save these URLs to disk in PowerShell, you can use the Invoke-WebRequest cmdlet to download the webpage, Out-File cmdlet to save it to disk, and then use a regular expression to parse the inner URLs. Here is a simple example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
$url
=
"http://example.com"
$outfile
=
"output.html"
$urlfile
=
"urls.txt"
Invoke-WebRequest
-Uri
$url
-OutFile
$outfile
$content
=
Get-Content
-Path
$outfile
$innerUrls
=
$content
|
Where-Object
{
$_
-match
"(http|https)://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?"
}
$innerUrls
|
Out-File
-FilePath
$urlfile
|
This script will download the webpage, save it to output.html, read the saved file, parse the inner URLs, and then save these URLs to urls.txt. You can adjust the regular expression in the Where-Object cmdlet to match the URLs you are interested in.
画外音: 我发现解析出来的内部 urls
不太对,于是查看了原始网页中的链接形式,又对 Cursor
提出了进一步的要求,这次是用中文提的。
Q:
解析匹配 href="xxx"
模式的字符串。
A:
要在 PowerShell
中下载 URL
,将其保存到磁盘,然后解析内部 URL
,并将这些 URL
保存到磁盘,您可以使用 Invoke-WebRequest cmdlet
下载网页,使用 Out-File cmdlet
将其保存到磁盘,然后使用正则表达式解析内部 URL
。以下是一个简单的示例:
1
2
3
4
5
6
7
|
$innerUrls
=
$content
|
Where-Object
{
$_
-match
'href="([^"]*)"'
}
$innerUrls
|
Out-File
-FilePath
$urlfile
|
此脚本将下载网页,将其保存到 output.html
,读取保存的文件,解析内部 URL
,然后将这些 URL
保存到 urls.txt
。您可以调整 Where-Object cmdlet
中的正则表达式以匹配您感兴趣的 URL
。
画外音: 非常不错,可以记住上下文。
Q:
解析内部 url
的语句有问题,没有只保存 href=""
内部的内容
A:
对不起,我之前的回答中的正则表达式确实有误。我们应该使用一个捕获组来只获取 href=""
内部的内容。以下是修正后的代码:
1
2
3
4
5
6
7
|
$innerUrls
=
$content
|
Select-String
-Pattern
'href="([^"]*)"'
-AllMatches
| % {
$_
.Matches } | % {
$_
.Groups[1].Value }
$innerUrls
|
Out-File
-FilePath
$urlfile
|
这段脚本将下载网页,将其保存到 output.html
,读取保存的文件,解析内部 URL
,然后将这些 URL
保存到 urls.txt
。Select-String cmdlet
中的正则表达式已经被修改,现在它只会匹配 href=""
内部的内容。
画外音: 看了生成的内容,已经无限接近最终想要的结果了,但是没想到居然写了 5000
多篇文章,手动拼接网址还是需要操作一会的。于是继续优化脚本。
Q:
需要在解析出来的 url 前加上前缀 再保存
A:
在解析出来的 URL
前加上前缀并保存的 PowerShell
代码如下:
1
2
3
4
5
6
7
8
|
$prefix
=
"https://bytepointer.com/resources/old_new_thing/"
$innerUrls
=
$innerUrls
|
ForEach-Object
{
$prefix
+
$_
}
$innerUrls
|
Out-File
-FilePath
$urlfile
|
这段脚本将下载网页,将其保存到 output.html
,读取保存的文件,解析内部 URL
,然后在每个 URL
前添加前缀,最后将这些 URL
保存到 urls.txt
。
至此,已经把需要下载的 url
保存到了 urls.txt
。接下来就要写脚本下载这些 url
了。最终载脚本如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
$url
=
"https://bytepointer.com/resources/old_new_thing/index.htm"
$outfile
=
"output.html"
$urlfile
=
"urls.txt"
Invoke-WebRequest
-Uri
$url
-OutFile
$outfile
$content
=
Get-Content
-Path
$outfile
$innerUrls
=
$content
|
Select-String
-Pattern
'href="([^"]*)"'
-AllMatches
| % {
$_
.Matches } | % {
$_
.Groups[1].Value }
$prefix
= "https://bytepointer.com/resources/old_new_thing/"
$innerUrls
=
$innerUrls
|
ForEach-Object
{
$prefix
+
$_
}
$innerUrls
|
Out-File
-FilePath
$urlfile
|
解析 url 并下载
Q:
遍历 urls.txt
并下载里面的每个 url
,如果下载失败需要有提示,并且记录下载的位置。
A:
在 PowerShell
中,你可以使用 Invoke-WebRequest cmdlet
来下载 URL
,并使用 try/catch
语句来处理可能的错误。以下是一个简单的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
$urlfile
=
"urls.txt"
$urls
=
Get-Content
-Path
$urlfile
foreach
(
$url
in
$urls
) {
$outfile
=
"downloaded_"
+
[System.IO.Path]
::GetFileName(
$url
)
try {
Invoke-WebRequest
-Uri
$url
-OutFile
$outfile
Write-Output
"Downloaded $url to $outfile"
} catch {
Write-Output
"Failed to download $url: $_"
}
}
|
画外音:
- 最后面的
Write-Output "Failed to download $url: $_"
会报错,需要在 $url
与 :
之间加空格。
- 保存的文件名我去掉了
downloaded_
前缀,而是保存到了 d:/downloaded/
目录下。
因为文件数量太多,全部放到一个目录下会比较乱,于是想着按年月进行分组整理。
按年月分组
Q:
遍历文件夹中的文件,文件名前 8
个字符是年月日,比如 20030722_001_why_do_you_have_to_click_the_start_button_to_shut_down.html
。从中提取出年份,月份,并且根据年份创建文件夹,然后根据月份创建子文件夹,并把对应的文件放到新建的文件夹中。
A:
这是一个 PowerShell
脚本的示例,它可以遍历文件夹中的文件,提取文件名前 8
个字符作为年份和月份,然后根据年份创建文件夹,根据月份创建子文件夹,并将对应的文件移动到新建的文件夹中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
$sourceDir
=
"C:\path\to\your\source\directory"
$destDir
=
"C:\path\to\your\destination\directory"
Get-ChildItem
$sourceDir
-File
|
ForEach-Object
{
$year
=
$_
.Name.Substring(0, 4)
$month
=
$_
.Name.Substring(4, 2)
$newDir
=
Join-Path
-Path
$destDir
-ChildPath
$year
-AdditionalChildPath
$month
if
(!(
Test-Path
$newDir
)) {
New-Item
-ItemType
Directory
-Path
$newDir
|
Out-Null
}
Move-Item
-Path
$_
.FullName
-Destination
$newDir
}
|
请将 $sourceDir
和 $destDir
替换为你的实际路径。这个脚本会遍历 $sourceDir
中的所有文件,提取文件名前 4
个字符作为年份,接着的 2
个字符作为月份,然后在 $destDir
中创建一个以年份命名的新文件夹,再在该文件夹下创建以月份命名的子文件夹,并将文件移动到新文件夹中。如果新文件夹已经存在,它将不会再次创建。
画外音: -AdditionalChildPath
好像不是一个合法的选项,是 AI
自己臆想出来的。于是手动修改代码如下:
$newDir = Join-Path -Path $destDir -ChildPath $year
$newDir = Join-Path -Path $newDir -ChildPath $month
压缩
Q:
遍历文件夹,并压缩
A:
你可以使用 PowerShell
的 Compress-Archive
命令来遍历文件夹并压缩文件。以下是一个示例:
1
2
3
4
5
6
7
8
9
|
$sourceDir
=
"C:\path\to\your\source\directory"
$destDir
=
"C:\path\to\your\destination\directory"
Get-ChildItem
$sourceDir
-Recurse
|
ForEach-Object
{
if
(
$_
.PSIsContainer) {
$zipFilePath
=
Join-Path
-Path
$destDir
-ChildPath
(
$_
.Name +
".zip"
)
Compress-Archive
-Path
$_
.FullName
-DestinationPath
$zipFilePath
}
}
|
请将 $sourceDir
和 $destDir
替换为你的实际路径。这个脚本会遍历 $sourceDir
中的所有文件和文件夹,如果是文件夹,就将其压缩为 .zip
文件,并保存到 $destDir
中。
画外音: 实际上我并不需要递归处理,去掉 -Recurse
选项即可。
总结
整个过程很舒服,基本上没写一行代码,只是做了一些改动及细节微调。就把整个功能实现了。整个过程不到 20
分钟。
关于 Cursor
的用法,也很简单,网上随便一搜就能搜到。ctrl+L
即可开启魔法!