用不到 40 行代码构建元标签抓取 API
您是否想过 Whatsapp 或 Telegram 等消息应用程序如何让您看到所发送链接的预览?
在这篇文章中,我们将使用Deno构建一个抓取 API ,它接受一个 URL 并检索它的元标记,这样我们就可以从几乎任何网站获取标题、描述、图像等字段。
例如:
curl https://metatags.deno.dev/api/meta?url=https://dev.to
将会得到这个结果
{
"last-updated": "2024-10-15 15:10:02 UTC",
"user-signed-in": "false",
"head-cached-at": "1719685934",
"environment": "production",
"description": "A constructive and inclusive social network for software developers. With you every step of your journey.",
"keywords": "software development, engineering, rails, javascript, ruby",
"og:type": "website",
"og:url": "https://dev.to/",
"og:title": "DEV Community",
"og:image": "https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8lvvnvil0m75nw7yi6iz.jpg",
"og:description": "A constructive and inclusive social network for software developers. With you every step of your journey.",
"og:site_name": "DEV Community",
"twitter:site": "@thepracticaldev",
"twitter:title": "DEV Community",
"twitter:description": "A constructive and inclusive social network for software developers. With you every step of your journey.",
"twitter:image:src": "https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8lvvnvil0m75nw7yi6iz.jpg",
"twitter:card": "summary_large_image",
"viewport": "width=device-width, initial-scale=1.0, viewport-fit=cover",
"apple-mobile-web-app-title": "dev.to",
"application-name": "dev.to",
"theme-color": "#000000",
"forem:name": "DEV Community",
"forem:logo": "https://media2.dev.to/cdn-cgi/image/width=512,height=,fit=scale-down,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j7kvp660rqzt99zui8e.png",
"forem:domain": "dev.to",
"title": "DEV Community"
}
很酷,不是吗?
元标签以及我们为什么需要它们
元标记是 HTML 元素,用于向搜索引擎和其他客户端提供有关页面的附加信息。
这些标记通常包含一个 name 或 property 属性(用于定义信息类型),以及一个 content 属性(用于包含该信息的值)。以下是两个元标记的示例:
<meta name="description" content="The <meta> HTML element represents metadata that cannot be represented by other HTML meta-related elements, like <base>, <link>, <script>, <style> or <title>.">
<meta property="og:image" content="https://developer.mozilla.org/mdn-social-share.cd6c4a5a.png">
第一个标签提供页面的描述,而第二个标签是 Open Graph 标签,用于定义在社交媒体上共享页面时显示的图像。
元标签的一个实际应用是构建书签管理器。无需手动为每个书签添加标题、描述和图片,您可以使用元标签自动从书签 URL 中抓取这些信息。
开放图谱
Open Graph 是一种互联网协议,最初由 Facebook 创建,旨在规范网页中元数据的使用,以呈现页面内容,帮助社交网络生成丰富的链接预览。点击此处
了解更多信息。
为什么选择 Deno?
- Deno 具有安全默认值,这意味着它需要对文件、网络和环境访问的明确许可,从而降低了安全漏洞的风险。
- Deno 基于 Web 标准构建,使用 ES 模块,旨在使用 Web 平台 API(如 fetch)而不是专有 API,这使得 Deno 代码与您在浏览器中编写的代码非常相似 - 但仍然与浏览器存在一些规范偏差。
- Deno 内置了 TypeScript 支持,允许您无需构建步骤即可编写 TypeScript 代码。
- Deno 带有一个标准库,其中包含用于常见任务的模块,例如 HTTP 服务器、文件系统操作等。
- Deno 提供了 Linter、Formatter 和 Test runner,允许您使用该平台而不是依赖第三方包或工具,使其成为 Javascript 开发的一体化工具。
- Deno 提供 Deno Deploy,这是一个可扩展的平台,适用于全球分布的无服务器 JavaScript/Typescript 应用程序,可确保最小的延迟和最大的正常运行时间。
我们正在构建的 API 将由两部分组成:用于获取和解析元标记的函数,以及响应 HTTP 请求的 API 服务器。
获取元标记
首先,我们进入Deno Deploy并登录。
登录后,点击“New Playground”。 这将为我们提供一个起点。 现在,我们将添加一个函数,该函数接受一个 URL,并使用 Fetch API 获取请求 URL 的 HTML,并将其传递给一个包进行 HTML 解析(deno-dom)。 要将其添加到我们的项目中,我们可以使用jsr包管理器:hello world
getMetaTags
deno-dom
import { DOMParser, Element } from "jsr:@b-fuze/deno-dom";
现在我们将使用 Fetch API 将 HTML 作为文本获取:
const headers = new Headers();
headers.set("accept", "text/html,application/xhtml+xml,application/xml");
const res = await fetch(url, { headers });
const html = await res.text();
获取 HTML 后,我们可以使用deno-dom
它来解析它,然后使用标准 DOM 函数来querySelectorAll
获取所有meta
HTML 元素,对它们进行迭代并用于getAttribute
获取每个标签的名称、属性和内容:
const document = new DOMParser().parseFromString(html, "text/html");
const metaTags = document.querySelectorAll("meta");
const documentMeta = (Array.from(metaTags) as Element[])
.reduce((acc, meta) => {
const property = meta.getAttribute("property");
...
最后,我们还将查询<title>
页面元素以将其作为字段添加到我们的 API 中:
documentMeta.title ??= document.querySelector("title").textContent;
它不完全是一个元标记,但我认为它是一个有用的字段,所以无论如何它都将成为我们 API 的一部分。:)
我们的最终getMetaTags
函数应该是这样的:
import { DOMParser, Element } from "jsr:@b-fuze/deno-dom";
const getMetaTags = async (url: string) => {
const headers = new Headers();
headers.set("accept", "text/html,application/xhtml+xml,application/xml");
const res = await fetch(url, { headers });
const html = await res.text();
const document = new DOMParser().parseFromString(html, "text/html");
const metaTags = document.querySelectorAll("meta");
const documentMeta = (Array.from(metaTags) as Element[])
.reduce((acc, meta) => {
const property = meta.getAttribute("property");
const name = meta.getAttribute("name");
const content = meta.getAttribute("content");
if (!content) return acc;
if (property) acc[property] = content;
if (name) acc[name] = content;
return acc;
}, {} as Record<string, string>);
documentMeta.title ??= document.querySelector("title").textContent;
return documentMeta;
};
服务器
为了简单起见,我决定使用 Deno 内置的 http 服务器,这只是一个简单的Deno.serve()
调用。
由于 deno 是基于 Web 标准构建的,我们可以使用Fetch API 中内置的 Response 对象来响应请求。
Deno.serve({ port: 8000 }, async (request: Request): Promise<Response> => {
const url = new URL(request.url);
if (request.method === "GET" && url.pathname === "/api/meta") {
const metaTags = await getMetaTags(url.searchParams.get("url"));
const headers = new Headers();
headers.set("Content-Type", "application/json");
headers.set("Access-Control-Allow-Origin", "*");
return new Response(JSON.stringify(metaTags), { status: 200, headers });
}
return new Response("not found", { status: 404 });
});
我们的服务器解析请求 url,检查我们是否收到了GET
对该/api/meta
路径的请求,并调用getMetaTags
我们创建的函数,然后将元标记作为响应主体返回。
我们还添加了两个标头,第一个标头是Content-Type
客户端需要知道他们在响应中获得的数据类型,在我们的例子中是 JSON 响应。
第二个标头Access-Control-Allow-Origin
允许我们的 API 接受来自特定来源的请求。在本例中,我选择"*"
接受任意来源,但您可能希望将其更改为仅接受来自您前端来源的请求。
请注意,CORS 标头只会影响浏览器发出的请求,这意味着浏览器会根据标头中指定的来源阻止请求,但仍然可以直接从服务器调用 API。点击此处了解更多关于 CORS 的信息。
您现在可以单击“保存并部署” ,然后等待 deno deploy 将您的代码部署到游乐场: 右上角的 url 是您的游乐场的 url,复制它并添加以查看其运行情况,url 应该看起来像 您现在应该看到 API 使用 的元标记进行响应!/api/meta?url=https://dev.to
https://metatags.deno.dev/api/meta?url=https://dev.to
dev.to
部署
使用 Deno deploy 的 Playground 意味着你的代码在技术上已经部署完毕,它是公开的,任何人都可以访问。
对于像我们正在构建的这种简单的 API,一个单文件 Playground 就足够了,但在很多情况下,我们希望进一步扩展项目,为此,你可以使用 Deno deploy 的 Github Export 为你的 API 创建一个合适的代码仓库,并支持在新代码推送时自动构建: 或者从 Playground 的设置中进行设置:
注意事项
本文介绍的抓取方法只适用于从服务器返回的 html 文件中具有元标记的网站,这意味着服务器渲染或预渲染的网站更有可能返回正确的结果,只要元标记是在构建时而不是在运行时设置的,单页应用程序也可以工作。
结论
我们演示了使用 Deno 构建和部署 API 是多么快速和简单,我们已经介绍了元标记,以及如何使用 Fetch API、DOM 解析器和 Deno 的内置服务器在不到 40 行代码中构建元标记抓取 API。
要查看此帖子中构建的项目,您可以查看Deno 部署游乐场(您需要添加/api/meta?url=https://dev.to
到右侧的 URL 栏才能查看示例响应)或此 github 存储库。
您下一步要建造什么?
希望这篇文章能激发您探索元标签和 Deno 的强大功能!尝试构建您自己的 API 版本,或将其集成到类似书签管理器的项目中。
遇到困难、有疑问,或者想展示你的成果?欢迎在下方留言或在Twitter/X上联系我——我期待您的反馈!
请查看我之前关于使用不到 40 行代码构建反应状态管理库的帖子。
文章来源:https://dev.to/paripsky/building-a-meta-tags-scraping-api-in-under-40-lines-of-code-1f57