p3k / xray
X-Ray 从任何 URL 返回结构化数据
Requires
- cebe/markdown: ^1.1.0
- ezyang/htmlpurifier: ^4.10
- indieweb/link-rel-parser: ^0.1.0
- masterminds/html5: ^2.3
- mf2/mf2: ^0.4||^0.5
- p3k/http: ^0.1.0
- p3k/picofeed: ^0.1.0
- p3k/timezone: ^0.1.0
Requires (Dev)
- league/plates: ^3.0
- league/route: ^1.0
- phpunit/phpunit: ^8.0.0|^9.0.0
- dev-main
- v1.15.1
- v1.15.0
- v1.14.1
- v1.14.0
- v1.13.0
- v1.12.0
- v1.11.1
- v1.11.0
- v1.10.6
- v1.10.5
- v1.10.4
- v1.10.3
- v1.10.2
- v1.10.1
- v1.10.0
- v1.9.3
- v1.9.1
- v1.9.0
- v1.8.2
- v1.8.1
- v1.8.0
- v1.7.1
- v1.7.0
- v1.6.9
- v1.6.8
- v1.6.7
- v1.6.6
- v1.6.5
- v1.6.4
- v1.6.3
- v1.6.2
- v1.6.1
- v1.6.0
- v1.5.1
- v1.5.0
- v1.4.35
- v1.4.34
- v1.4.33
- v1.4.32
- v1.4.31
- v1.4.30
- v1.4.29
- v1.4.28
- v1.4.27
- v1.4.26
- v1.4.25
- v1.4.23
- v1.4.22
- v1.4.21
- v1.4.20
- v1.4.19
- v1.4.18
- v1.4.17
- v1.4.16
- v1.4.15
- v1.4.14
- v1.4.13
- v1.4.12
- v1.4.11
- v1.4.10
- v1.4.9
- v1.4.8
- v1.4.7
- v1.4.6
- v1.4.5
- v1.4.4
- v1.4.2
- v1.4.1
- v1.4.0
- v1.3.1
- v1.3.0
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.1
- v1.1.0
- v1.0.0
- dev-master
This package is auto-updated.
Last update: 2024-08-31 16:22:08 UTC
README
XRay 解析来自 URL 的结构化内容。
发现内容
XRay 将解析以下格式的内容。首先将 URL 与已知服务进行核对
- GitHub
- XKCD
- Hackernews
如果 URL 的内容是 XML 或 JSON,则 XRay 将解析 Atom、RSS 或 JSONFeed 格式。
最后,XRay 将在页面上查找 Microformats,并据此确定内容。
- h-card
- h-entry
- h-event
- h-review
- h-recipe
- h-product
- h-item
- h-feed
库
XRay 可以作为 PHP 项目中的库使用。最简单的安装方法是使用 composer。
composer require p3k/xray
您还可以 下载一个发行版 ,这是一个包含所有依赖项的 zip 文件。
解析
$xray = new p3k\XRay(); $parsed = $xray->parse('https://aaronparecki.com/2017/04/28/9/');
如果您已经有了一个要解析的 HTML 或 JSON 文档,您可以将它作为字符串传递到第二个参数中。
$xray = new p3k\XRay(); $html = '<html>....</html>'; $parsed = $xray->parse('https://aaronparecki.com/2017/04/28/9/', $html);
$xray = new p3k\XRay(); $jsonfeed = '{"version":"https://jsonfeed.org/version/1","title":"Manton Reece", ... '; // Note that the JSON document must be passed in as a string in this case $parsed = $xray->parse('https://manton.micro.blog/feed.json', $jsonfeed);
在这两种情况下,您都可以添加一个额外的参数来配置 XRay 的各种行为选项。以下是一个选项列表。
timeout
- 等待任何 HTTP 请求的超时时间(秒)max_redirects
- 要遵循的最大重定向数include_original
- 也会返回获取的完整文档target
- 指定一个目标 URL,XRay 首先会检查该 URL 是否在页面上,如果是,则继续解析页面。这对于您使用 XRay 验证传入的 webmention 非常有用。expect=feed
- 如果您知道您正在解析的内容是一个源,包含此参数可以避免运行自动检测规则,并将为某些源提供更好的结果。accept
- (选项:html
、json
、activitypub
、xml
) - 如果没有此参数,XRay 会发送一个默认的Accept
标头,以便从页面上获取最有可能的最佳结果。如果您正在解析页面以进行特定目的,并期望找到特定类型的内容(例如,webmentions 很可能只来自 HTML 页面),则可以包含此参数以调整 XRay 发送的Accept
标头。
在使用 GitHub API 进行请求时,支持额外的参数。有关详细信息,请参阅下面的身份验证部分。
XRay 构造函数可以可选地传递一个默认选项数组,这些选项将应用于(并且可以由传递给单个 parse()
调用的选项覆盖)。
$xray = new p3k\XRay([ 'timeout' => 30 // Time-out all requests which take longer than 30s ]); $parsed = $xray->parse('https://aaronparecki.com/2017/04/28/9/', [ 'timeout' => 40 // Override the default 30s timeout for this specific request ]); $parsed = $xray->parse('https://aaronparecki.com/2017/04/28/9/', $html, [ 'target' => 'http://example.com/' ]);
$parsed
返回值将如下所示。有关返回的词汇表的解释,请参阅下面的“主要数据”。
$parsed = Array
(
[data] => Array
(
[type] => card
[name] => Aaron Parecki
[url] => https://aaronparecki.com/
[photo] => https://aaronparecki.com/images/profile.jpg
)
[url] => https://aaronparecki.com/
[code] => 200,
[source-format] => mf2+html
)
处理 Microformats2 JSON
如果您已经有一个解析后的 Microformats2 文档作为数组,您可以使用一个特殊函数将其处理成 XRay 的原生格式。确保您传递整个解析后的文档,而不仅仅是单个项。
$html = '<div class="h-entry"><p class="p-content p-name">Hello World</p><img src="/photo.jpg"></p></div>'; $mf2 = Mf2\parse($html, 'http://example.com/entry'); $xray = new p3k\XRay(); $parsed = $xray->process('http://example.com/entry', $mf2); // note the use of `process` not `parse` Array ( [data] => Array ( [type] => entry [post-type] => photo [photo] => Array ( [0] => http://example.com/photo.jpg ) [content] => Array ( [text] => Hello World ) ) [url] => http://example.com/entry [source-format] => mf2+json )
Rels
您还可以使用 XRay 获取页面上的所有 rel 值,将 HTTP Link
标头的 rel 值与页面的 HTML rel 值合并。
$xray = new p3k\XRay(); $rels = $xray->rels('https://aaronparecki.com/');
这将返回与解析器类似的结果,但与包含解析页面的 data
键不同,将有一个 rels
,这是一个关联数组。每个键将包含匹配该 rel 值的所有值的数组。
Array
(
[url] => https://aaronparecki.com/
[code] => 200
[rels] => Array
(
[hub] => Array
(
[0] => https://switchboard.p3k.io/
)
[authorization_endpoint] => Array
(
[0] => https://aaronparecki.com/auth
)
...
内容发现
您可以使用XRay来发现URL中可用的内容类型。
$xray = new p3k\XRay(); $feeds = $xray->feeds('http://percolator.today');
这将获取URL,检查是否存在Microformats内容,同时检查是否存在指向Atom、RSS或JSONFeed URL的rel=alternates链接。响应将如下所示。
Array
(
[url] => https://percolator.today/
[code] => 200
[feeds] => Array
(
[0] => Array
(
[url] => https://percolator.today/
[type] => microformats
)
[1] => Array
(
[url] => https://percolator.today/podcast.xml
[type] => rss
)
)
)
自定义用户代理
要设置唯一的用户代理(某些网站可能需要设置用户代理),可以将对象的http
属性设置为p3k\HTTP
对象。
$xray = new p3k\XRay(); $xray->http = new p3k\HTTP('MyProject/1.0.0 (http://example.com/)'); $xray->parse('http://example.com/');
API
XRay也可以作为API,通过HTTP服务提供其解析能力。
要解析页面并返回页面内容的结构化数据,只需将URL传递给/parse
路由。
GET /parse?url=https://aaronparecki.com/2016/01/16/11/
要首先检查页面是否包含指向目标URL的链接后再条件性地解析页面,请包含目标URL作为参数。当使用XRay验证传入的webmention时,这很有用。
GET /parse?url=https://aaronparecki.com/2016/01/16/11/&target=http://example.com
在这两种情况下,响应将是一个包含“type”键的JSON对象。如果发生错误,“type”将设置为字符串“error”,否则它将指向在URL中找到的内容类型,通常是“entry”。
您也可以使用相同的参数名称进行POST请求。
如果您已经有了要解析的HTML或JSON文档,您可以将它包含在POST参数body
中。此POST请求如下所示
POST /parse
Content-type: application/x-www-form-urlencoded
url=https://aaronparecki.com/2016/01/16/11/
&body=<html>....</html>
或者对于GitHub,您可能已经有了JSON
POST /parse
Content-type: application/x-www-form-urlencoded
url=https://github.com/aaronpk/XRay
&body={"repo":......}
参数
当调用/parse
时,XRay接受以下参数
url
- 要解析的页面的URLtarget
- 指定一个目标 URL,XRay 首先会检查该 URL 是否在页面上,如果是,则继续解析页面。这对于您使用 XRay 验证传入的 webmention 非常有用。timeout
- 等待任何 HTTP 请求的超时时间(秒)max_redirects
- 要遵循的最大重定向数include_original
- 也会返回获取的完整文档expect=feed
- 如果您知道您正在解析的内容是一个源,包含此参数可以避免运行自动检测规则,并将为某些源提供更好的结果。
身份验证
如果获取的URL需要身份验证,请将访问令牌包含在“token”参数中,它将在获取URL时包含在“Authorization”头中。(在这种情况下建议使用POST请求,以避免访问令牌可能被作为查询字符串的一部分记录。)这对于私有Webmention验证很有用。
POST /parse
url=https://aaronparecki.com/2016/01/16/11/
&target=http://example.com
&token=12341234123412341234
API身份验证
XRay使用GitHub API获取帖子,这些API需要身份验证。为了保持XRay无状态,需要将凭据传递给解析调用。
您应该仅在要解析的URL是GitHub URL时发送凭据,因此您在包含凭据之前需要检查主机名是否为github.com
等。
GitHub身份验证
XRay使用GitHub API获取GitHub URL,当使用身份验证时,它提供了更高的速率限制。您可以在请求中传递GitHub访问令牌,XRay将在对API进行请求时使用它。
github_access_token
- GitHub访问令牌
错误响应
{ "error": "not_found", "error_description": "The URL provided was not found" }
以下列出了可能的错误
not_found
:提供的URL未找到。(获取时返回404)ssl_cert_error
:验证SSL证书时出错。这可能会发生如果SSL证书已过期。ssl_unsupported_cipher
:Web服务器不支持服务已知的所有SSL密码。timeout
:服务尝试连接到URL时超时。invalid_content
:URL上的内容无效。例如,提供指向图像的URL将返回此错误。no_link_found
:在页面上未找到目标链接。当提供目标参数时,如果在页面上找不到目标,将返回此错误。no_content
:在给定的URL上找不到可用的内容。unauthorized
:URL返回HTTP 401未授权。forbidden
:URL返回HTTP 403禁止。
响应格式
{ "data":{ "type":"entry", "post-type":"photo", "published":"2017-03-01T19:00:33-08:00", "url":"https://aaronparecki.com/2017/03/01/14/hwc", "category":[ "indieweb", "hwc" ], "photo":[ "https://aaronparecki.com/2017/03/01/14/photo.jpg" ], "syndication":[ "https://twitter.com/aaronpk/status/837135519427395584" ], "content":{ "text":"Hello from Homebrew Website Club PDX! Thanks to @DreamHost for hosting us! 🍕🎉 #indieweb", "html":"Hello from Homebrew Website Club PDX! Thanks to <a href=\"https://twitter.com/DreamHost\">@DreamHost</a> for hosting us! <a href=\"https://aaronparecki.com/emoji/%F0%9F%8D%95\">🍕</a><a href=\"https://aaronparecki.com/emoji/%F0%9F%8E%89\">🎉</a> <a href=\"https://aaronparecki.com/tag/indieweb\">#indieweb</a>" }, "author":{ "type":"card", "name":"Aaron Parecki", "url":"https://aaronparecki.com/", "photo":"https://aaronparecki.com/images/profile.jpg" } }, "url":"https://aaronparecki.com/2017/03/01/14/hwc", "code":200, "source-format":"mf2+html" }
主要数据
页面上的主要对象保存在 data
属性中。这会指示对象的类型(例如 entry
),并且将包含它从页面中解析出的词汇的属性。
type
- 在页面上的主要对象中找到的 Microformats 2 词汇,没有h-
前缀(例如entry
、event
)post-type
- 仅适用于 "posts"(例如,不适用于card
)- 文章的 类型(例如note
、photo
、reply
)
如果属性支持多个值,它将始终以数组形式返回。以下属性支持多个值
in-reply-to
like-of
repost-of
bookmark-of
follow-of
syndication
photo
(条目的照片,而非卡片的照片)video
audio
category
内容将是一个对象,它始终包含一个 "text" 属性,如果源文档发布了 HTML 内容,则可能包含一个 "html" 属性。在将其作为 HTML 显示之前,必须始终对 "text" 属性进行 HTML 转义,因为它可能包含未转义的字符,如 <
和 >
。
如果可用,作者将始终在条目中设置。服务遵循 作者发现 算法,以尝试在源文档的条目之外的其他地方找到作者信息。
输出中提供的所有 URL 都是绝对 URL。如果源文档包含相对 URL,则首先将其解析。
文章类型发现
XRay 运行 文章类型发现 算法,还包括一个 post-type
属性。
以下文章类型被返回,这略微超出了当前由文章类型发现规范所记录的内容。
event
recipe
review
rsvp
repost
like
reply
bookmark
follow
checkin
video
audio
photo
article
note
其他属性
其他属性与 data
属性在相同的级别返回。
url
- 从中检索文档的有效 URL。这将是在跟随任何重定向后的最终 URL。code
- URL 返回的 HTTP 响应代码。通常这将是一个 200,但如果 URL 返回了包含 h-entry 的其他 HTTP 代码(例如,包含 stub h-entry 的 410 已删除通知),则可以使用此代码了解原始 URL 实际上已被删除。source-format
- 指示用于生成解析结果的源 URL 的格式。可能的值包括mf2+html
mf2+json
feed+json
xml
github
/xkcd
源
XRay 可以返回几种不同类型的源信息。传递给 XRay 的 URL(或正文)将检查以下格式
- XML(Atom 和 RSS)
- JSONFeed (https://jsonfeed.org)
- Microformats h-feed
如果正在解析的页面代表一个源,则响应将如下所示
{ "data": { "type": "feed", "items": [ {...}, {...} ] } }
items
数组中的每个对象都包含一个项目的解析版本,其格式与 XRay 通常返回的格式相同。当解析 Microformats 源时,将为每个项目运行 作者发现 以构建作者信息。
Atom、RSS 和 JSONFeed 都将规范化为 XRay 的词汇,并且仅返回已识别的属性。
关系API
还有一个API方法可以解析并返回页面上的所有rel值,包括HTTP Link
头和HTML rel值。
GET /rels?url=https://aaronparecki.com/
关于响应格式,请参阅上面。
内容发现API
GET /feeds?url=https://aaronparecki.com/
关于响应格式,请参阅上面。
令牌API
在验证私有Webmention时,您需要在源URL指定的令牌端点处交换代码以获取访问令牌。
XRay提供了一个API,可以一步完成此操作。您可以提供从webmention获得的源URL和代码,XRay将发现令牌端点,然后返回访问令牌。
POST /token
source=http://example.com/private-post
&code=1234567812345678
响应将是令牌端点的响应,其中将包括一个access_token
属性,以及可能的一个expires_in
属性。
{
"access_token": "eyJ0eXAXBlIjoI6Imh0dHB8idGFyZ2V0IjoraW0uZGV2bb-ZO6MV-DIqbUn_3LZs",
"token_type": "bearer",
"expires_in": 3600
}
如果在获取访问令牌时出现问题,您将除了从解析API返回的与HTTP相关的错误之外,还会收到以下错误之一
no_token_endpoint
- 无法找到指定令牌端点的HTTP头。
安装
从源代码
# Clone this repository
git clone git@github.com:aaronpk/XRay.git
cd XRay
# Install dependencies
composer install
从ZIP存档
- 从https://github.com/aaronpk/XRay/releases下载最新版本
- 解压缩到您的Web服务器上的一个文件夹
Web服务器配置
将您的Web服务器配置为指向public
文件夹。
确保所有请求都路由到index.php
。XRay附带了Apache的.htaccess
文件。对于nginx,您需要在您的服务器配置块中添加如下规则。
try_files $uri /index.php?$args;