Wait no longer! Create RSS feeds for all websites you care about and read them from the comfort of your feed reader.
Сейчас все больше и больше веб-сайтов не поддерживают подписку на RSS, и, как преданный поклонник RSS, я все еще надеюсь, что существует инструмент, который может собирать содержимое веб-сайтов, за которыми я слежу, а затем передавать его на мобильный телефон в режиме реального времени. чтобы получать последние новости и новости в динамике во времени.
Итак, сегодня давайте потратим 2 часа на создание генератора RSS.
Главный герой этой статьи по-прежнему Laravel.
1. Создайте скелет Laravel
Поскольку нам нужен фон для добавления нужных нам веб-сайтов, мы по-прежнему используем плагин laravel-admin.
// 1. 创建 Laravel 5.5版本项目
composer create-project --prefer-dist laravel/laravel:5.5 lrss
cd lrss
cp .env.example .env
php artisan key:generate
// 2. 使用 laravel-admin 插件
composer require encore/laravel-admin "1.5.*"
php artisan vendor:publish --provider="Encore\Admin\AdminServiceProvider"
php artisan admin:install
*Примечание: *В случае возникновения проблемы: SQLSTATE[42000]: синтаксическая ошибка или нарушение прав доступа: 1071 Указанный ключ слишком длинный, максимальная длина ключа составляет 767 байт.
Решение: вAppServiceProvider.php
Добавить длину строки по умолчанию
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}
Как оказалось, мы хотим воспользоваться преимуществами Symfonys.DomCrawler
Плагин для анализа информации xpath веб-сайта, найтиlaravel-admin
Плагин представил:
2. Разобрать XPath
Раньше я хотел использовать артефакт Huginn для создания нашего RSS-канала, в основном ссылаясь на статью: Превратите все веб-страницы в RSS - Huginngit.Hu Ginn.cai/docs/%E8%AE…
Но при фактическом использовании обнаруживается, что Huginn не работает без причины, или фоновые задания терпят неудачу на каждом шагу. Вот так у меня появилась идея создать свой собственный инструмент.
Но Хьюгинн вдохновил меня на использование синтаксического анализа XPath для создания RSS-каналов.
Создайте контроллер Xpath
Чтобы проверить точность входной информации XPath, мы можем обратиться к Huginn,
Сначала проверьте действие XPath в Huginn.В интерфейсе Create WebsiteAgent введите следующую информацию:
{
"expected_update_period_in_days": "2",
"url": "http://www.woshipm.com/",
"type": "html",
"mode": "on_change",
"extract": {
"title": {
"xpath": "//div[@class=\"postlist-item u-clearfix\"]/div[2]/h2/a/text()",
"value": "normalize-space(.)"
},
"desc": {
"xpath":
"//div[@class=\"postlist-item u-clearfix\"]/div[2]/p/text()",
"value": "normalize-space(.)"
},
"url": {
"xpath": "//div[@class=\"postlist-item u-clearfix\"]/div[2]/h2/a",
"value": "@href"
}
}
}
Затем нажмите «Пробный прогон», чтобы проверить:
Наконец, в соответствии с информацией, заполненной Huginn, давайте создадим контроллер Xpath.
// bash
php artisan make:model Xpath -m
// migration
public function up()
{
Schema::create('xpaths', function (Blueprint $table) {
$table->increments('id');
// url
$table->string('url', 250);
$table->string("urldesc", 250);
// title
$table->string('titlexpath', 250);
$table->string('titlevalue', 100)
->nullable();
// desc
$table->string('descxpath', 250);
$table->string('descvalue', 100)
->nullable();
// url
$table->string("preurl", 50)->nullable();
$table->string('urlxpath', 250);
$table->string('urlvalue', 100)
->nullable();
$table->timestamps();
});
}
// migrate
php artisan migrate
// 创建 admin/Controller
php artisan admin:make XpathController --model=App\\Xpath
// 建立 route
$router->resource('xpaths', XpathController::class);
// 加入到 admin 的 menu 中
// 略
Примечание:Вы можете обратиться к предыдущим статьям:Порекомендуйте плагин управления фоном администратора Laravel
CURD XPath
С плагином laravel-admin легко манипулировать информацией XPath, просто взгляните на код:
<?php
namespace App\Admin\Controllers;
use App\Xpath;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Encore\Admin\Facades\Admin;
use Encore\Admin\Layout\Content;
use App\Http\Controllers\Controller;
use Encore\Admin\Controllers\ModelForm;
class XpathController extends Controller
{
use ModelForm;
/**
* Index interface.
*
* @return Content
*/
public function index()
{
return Admin::content(function (Content $content) {
$content->header('header');
$content->description('description');
$content->body($this->grid());
});
}
/**
* Edit interface.
*
* @param $id
* @return Content
*/
public function edit($id)
{
return Admin::content(function (Content $content) use ($id) {
$content->header('header');
$content->description('description');
$content->body($this->form()->edit($id));
});
}
/**
* Create interface.
*
* @return Content
*/
public function create()
{
return Admin::content(function (Content $content) {
$content->header('header');
$content->description('description');
$content->body($this->form());
});
}
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Admin::grid(Xpath::class, function (Grid $grid) {
$grid->id('ID')->sortable();
$grid->column('url');
$grid->column('urldesc', "描述");
$grid->column('titlexpath');
$grid->column('titlevalue');
$grid->column('descxpath');
$grid->column('descvalue');
$grid->column('preurl');
$grid->column('urlxpath');
$grid->column('urlvalue');
$grid->created_at();
$grid->updated_at();
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Admin::form(Xpath::class, function (Form $form) {
$form->display('id', 'ID');
// url
$form->text('url', '链接')
->placeholder('请输入解析的网址')
->rules('required|min:5|max:250');
$form->text('urldesc', '一句话描述')
->placeholder('一句话描述')
->rules('required|min:5|max:250');
// title
$form->divide();
$form->text('titlexpath', 'title xpath')
->placeholder('请输入标题 xpath')
->rules('required|min:5|max:250');
$form->text('titlevalue', 'title value 默认可以不填')
->default('')
->rules('max:100');
// desc
$form->divide();
$form->text('descxpath', 'desc xpath')
->placeholder('请输入详情 xpath')
->rules('required|min:5|max:250');
$form->text('descvalue', 'desc value,默认可以不填')
->default('')
->rules('max:100');
// url
$form->divide();
$form->text('preurl', 'url 前缀')
->placeholder('请输入文章的url 前缀')
->rules('max:50');
$form->text('urlxpath', 'url xpath')
->placeholder('请输入文章的url xpath')
->rules('required|min:5|max:250');
$form->text('urlvalue', 'url value 默认可以不填')
->default('')
->rules('max:100');
$form->divide();
$form->display('created_at', 'Created At');
$form->display('updated_at', 'Updated At');
});
}
}
Попробуйте добавить две информации о веб-сайте:
XPath к RSS-каналу
1.В соответствии с заполненной информацией Xpath проанализируйте содержимое:
public static function analysis(XpathModel $model) {
$html = file_get_contents($model->url);
$crawler = new Crawler($html);
$titlenodes = $crawler->filterXPath($model->titlexpath);
$titles = self::getValueByNodes($titlenodes, $model->titlevalue);
$descnodes = $crawler->filterXPath($model->descxpath);
$desces = self::getValueByNodes($descnodes, $model->descvalue);
$urlnodes = $crawler->filterXPath($model->urlxpath);
$urls = self::getValueByNodes($urlnodes, $model->urlvalue);
return RssFeeds::feeds($model, $titles, $desces, $urls);
}
// 通过规则获取 nodes 的值
public static function getValueByNodes(Crawler $crawler, $key = null) {
return $crawler->each(function (Crawler $node) use ($key) {
if (empty($key)) {
return trim($node->text());
} else {
return $node->attr($key);
}
});
}
2.Загрузите полученные массивы title, desc и url в элемент фида, чтобы построить RSS.
public static function feeds(Xpath $xpath, $titles = [], $desces = [], $urls = []) {
if (!empty($xpath->preurl)) {
$preurl = $xpath->preurl;
$urlss = collect($urls)->map(function ($url, $key) use ($preurl) {
return $preurl.trim($url);
});
} else {
$urlss = collect($urls);
}
return response()
->view('rss',
[
'xpath' => $xpath,
'titles' => $titles,
'desces' => $desces,
'urls' => $urlss->toArray(),
'pubDate' => Carbon::now()
])
->header('Content-Type', 'text/xml');
}
3.Напишите шаблон блейда
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ $xpath->url or ' title' }}</title>
<description>{{ $xpath->urldesc or '描述' }}</description>
<link>{{ $xpath->url }}</link>
<atom:link href="{{ url("/feed/$xpath->id") }}" rel="self" type="application/rss+xml"/>
<pubDate>{{ $pubDate }}</pubDate>
<lastBuildDate>{{ $pubDate }}</lastBuildDate>
<generator>coding01</generator>
@foreach ($titles as $key => $title)
<item>
<title>{{ $title }}</title>
<link>{{ $urls[$key] }}</link>
<description>{{ $desces[$key] }}</description>
<pubDate>{{ $pubDate }}</pubDate>
<author>coding01</author>
<guid>{{ $urls[$key] }}</guid>
<category>{{ $title }}</category>
</item>
@endforeach
</channel>
</rss>
4.Наконец, давайте посмотрим на эффект, создадим RSS для каждого сайта:
RSS-подписка в прямом эфире
На данный момент текущий код Laravel подошел к концу, но для достижения цели своевременной доставки контента на мобильный телефон я использовал два инструмента:
- Tiny Tiny RSS
- IFTTT + DingTalk
Добавьте подготовленную RSS-ссылку в Tiny Tiny RSS и обновляйте ее каждые полчаса, чтобы получать самый свежий контент:
Затем используйте IFTTT для привязки группового робота DingTalk Webhook:
Наконец, вы можете своевременно получать последние новости и информацию на мобильный телефон DingTalk или на ПК:
Суммировать
Сегодня я потратил 2 часа, в основном используя плагины laravel-amin и symfony/dom-crawler для создания демо инструмента генерации RSS-каналов.
Остается оптимизировать в будущем, например,feed43.com/Таким образом, вы можете создавать RSS-каналы, вводя URL-адрес в Интернете, а также устанавливать время обновления в соответствии с фактическими потребностями.
Наконец, код можно разместить на github для ознакомления:github.com/fanly/lrss
"Продолжение следует"