Git Product home page Git Product logo

html2rss / html2rss-web Goto Github PK

View Code? Open in Web Editor NEW
80.0 4.0 11.0 647 KB

🕸 Create custom RSS feeds from any website with ease! Quick setup with Docker. Use built-in configs or tailor your own. Stay updated effortlessly.

Home Page: https://html2rss.github.io/components/html2rss-web

License: MIT License

Ruby 80.24% Dockerfile 4.52% Shell 0.68% XSLT 6.75% CSS 2.80% HTML 4.28% JavaScript 0.61% Procfile 0.12%
html2rss ruby docker scraper rss feed builder website-scraper rss-feed-scraper html2rss-configs

html2rss-web's Introduction

html2rss logo

Gem Version Yard Docs Retro Badge: valid RSS

html2rss is a Ruby gem that generates RSS 2.0 feeds from a feed config.

With the feed config, you provide a URL to scrape and CSS selectors for extracting information (like title, URL, etc.). The gem builds the RSS feed accordingly. Extractors and chainable post processors make information extraction, processing, and sanitizing a breeze. The gem also supports scraping JSON responses and setting HTTP request headers.

Looking for a ready-to-use app to serve generated feeds via HTTP? Check out html2rss-web!

Support the development by sponsoring this project on GitHub. Thank you! 💓

Installation

Install gem install html2rss
Usage html2rss help

You can also install it as a dependency in your Ruby project:

🤩 Like it? Star it! ⭐️
Add this line to your Gemfile: gem 'html2rss'
Then execute: bundle
In your code: require 'html2rss'

Generating a feed on the CLI

Create a file called my_config_file.yml with this example content:

channel:
  url: https://stackoverflow.com/questions
selectors:
  items:
    selector: "#hot-network-questions > ul > li"
  title:
    selector: a
  link:
    selector: a
    extractor: href

Build the RSS with: html2rss feed ./my_config_file.yml.

Generating a feed with Ruby

Here's a minimal working example in Ruby:

require 'html2rss'

rss =
  Html2rss.feed(
    channel: { url: 'https://stackoverflow.com/questions' },
    selectors: {
      items: { selector: '#hot-network-questions > ul > li' },
      title: { selector: 'a' },
      link: { selector: 'a', extractor: 'href' }
    }
  )

puts rss

The feed config and its options

A feed config consists of a channel and a selectors hash. The contents of both hashes are explained below.

Good to know:

  • You'll find extensive example feed configs at spec/*.test.yml.
  • See html2rss-configs for ready-made feed configs!
  • If you've created feed configs, you're invited to send a PR to html2rss-configs to make your config available to the public.

Alright, let's move on.

The channel

attribute type default remark
url required String
title optional String auto-generated
description optional String auto-generated
ttl optional Integer 360 TTL in minutes
time_zone optional String 'UTC' TimeZone name
language optional String 'en' Language code
author optional String Format: email (Name)
headers optional Hash {} Set HTTP request headers. See notes below.
json optional Boolean false Handle JSON response. See notes below.

Dynamic parameters in channel attributes

Sometimes there are structurally similar pages with different URLs. In such cases, you can add dynamic parameters to the channel's attributes.

Example of a dynamic id parameter in the channel URLs:

channel:
  url: "http://domainname.tld/whatever/%<id>s.html"

Command line usage example:

bundle exec html2rss feed the_feed_config.yml id=42
See a Ruby example
config = Html2rss::Config.new({ channel: { url: 'http://domainname.tld/whatever/%<id>s.html' } }, {}, { id: 42 })
Html2rss.feed(config)

See the more complex formatting options of the sprintf method.

The selectors

First, you must give an items selector hash, which contains a CSS selector. The selector selects a collection of HTML tags from which the RSS feed items are built. Except for the items selector, all other keys are scoped to each item of the collection.

To build a valid RSS 2.0 item, you need at least a title or a description. You can have both.

Having an items and a title selector is enough to build a simple feed.

Your selectors hash can contain arbitrary named selectors, but only a few will make it into the RSS feed (due to the RSS 2.0 specification):

RSS 2.0 tag name in html2rss remark
title title
description description Supports HTML.
link link A URL.
author author
category categories See notes below.
guid guid Default title/description. See notes below.
enclosure enclosure See notes below.
pubDate updated An instance of Time.
comments comments A URL.
source source Not yet supported.

The selector hash

Every named selector in your selectors hash can have these attributes:

name value
selector The CSS selector to select the tag with the information.
extractor Name of the extractor. See notes below.
post_process A hash or array of hashes. See notes below.

Using extractors

Extractors help with extracting the information from the selected HTML tag.

  • The default extractor is text, which returns the tag's inner text.
  • The html extractor returns the tag's outer HTML.
  • The href extractor returns a URL from the tag's href attribute and corrects relative ones to absolute ones.
  • The attribute extractor returns the value of that tag's attribute.
  • The static extractor returns the configured static value (it doesn't extract anything).
  • See file list of extractors.

Extractors might need extra attributes on the selector hash. 👉 Read their docs for usage examples.

See a Ruby example
Html2rss.feed(
  channel: {}, selectors: { link: { selector: 'a', extractor: 'href' } }
)
See a YAML feed config example
channel:
  # ... omitted
selectors:
  # ... omitted
  link:
    selector: "a"
    extractor: "href"

Using post processors

Extracted information can be further manipulated with post processors.

name
gsub Allows global substitution operations on Strings (Regexp or simple pattern).
html_to_markdown HTML to Markdown, using reverse_markdown.
markdown_to_html converts Markdown to HTML, using kramdown.
parse_time Parses a String containing a time in a time zone.
parse_uri Parses a String as URL.
sanitize_html Strips unsafe and uneeded HTML and adds security related attributes.
substring Cuts a part off of a String, starting at a position.
template Based on a template, it creates a new String filled with other selectors values.

⚠️ Always make use of the sanitize_html post processor for HTML content. Never trust the internet! ⚠️

Chaining post processors

Pass an array to post_process to chain the post processors.

YAML example: build the description from a template String (in Markdown) and convert that Markdown to HTML
channel:
  # ... omitted
selectors:
  # ... omitted
  price:
    selector: '.price'
  description:
    selector: '.section'
    post_process:
      - name: template
        string: |
          # %{self}

          Price: %{price}
      - name: markdown_to_html

Post processor gsub

The post processor gsub makes use of Ruby's gsub method.

key type required note
pattern String yes Can be Regexp or String.
replacement String yes Can be a backreference.
See a Ruby example
Html2rss.feed(
  channel: {},
  selectors: {
    title: { selector: 'a', post_process: [{ name: 'gsub', pattern: 'foo', replacement: 'bar' }] }
  }
)
See a YAML feed config example
channel:
  # ... omitted
selectors:
  # ... omitted
  title:
    selector: "a"
    post_process:
      - name: "gsub"
        pattern: "foo"
        replacement: "bar"

Adding <category> tags to an item

The categories selector takes an array of selector names. Each value of those selectors will become a <category> on the RSS item.

See a Ruby example
Html2rss.feed(
  channel: {},
  selectors: {
    genre: {
      # ... omitted
      selector: '.genre'
    },
    branch: { selector: '.branch' },
    categories: %i[genre branch]
  }
)
See a YAML feed config example
channel:
  # ... omitted
selectors:
  # ... omitted
  genre:
    selector: ".genre"
  branch:
    selector: ".branch"
  categories:
    - genre
    - branch

Custom item GUID

By default, html2rss generates a GUID from the title or description.

If this does not work well, you can choose other attributes from which the GUID is build. The principle is the same as for the categories: pass an array of selectors names.

In all cases, the GUID is a SHA1-encoded string.

See a Ruby example
Html2rss.feed(
  channel: {},
  selectors: {
    title: {
      # ... omitted
      selector: 'h1'
    },
    link: { selector: 'a', extractor: 'href' },
    guid: %i[link]
  }
)
See a YAML feed config example
channel:
  # ... omitted
selectors:
  # ... omitted
  title:
    selector: "h1"
  link:
    selector: "a"
    extractor: "href"
  guid:
    - link

Adding an <enclosure> tag to an item

An enclosure can be any file, e.g. a image, audio or video - think Podcast.

The enclosure selector needs to return a URL of the content to enclose. If the extracted URL is relative, it will be converted to an absolute one using the channel's URL as base.

Since html2rss does no further inspection of the enclosure, its support comes with trade-offs:

  1. The content-type is guessed from the file extension of the URL.
  2. If the content-type guessing fails, it will default to application/octet-stream.
  3. The content-length will always be undetermined and therefore stated as 0 bytes.

Read the RSS 2.0 spec for further information on enclosing content.

See a Ruby example
Html2rss.feed(
  channel: {},
  selectors: {
    enclosure: { selector: 'audio', extractor: 'attribute', attribute: 'src' }
  }
)
See a YAML feed config example
channel:
  # ... omitted
selectors:
  # ... omitted
  enclosure:
    selector: "audio"
    extractor: "attribute"
    attribute: "src"
## Scraping and handling JSON responses

By default, html2rss assumes the URL responds with HTML. However, it can also handle JSON responses. The JSON must return an Array or Hash.

key required default note
json optional false If set to true, the response is parsed as JSON.
jsonpath optional $ Use JSONPath syntax to select nodes of interest.
See a Ruby example
Html2rss.feed(
  channel: { url: 'http://domainname.tld/whatever.json', json: true },
  selectors: { title: { selector: 'foo' } }
)
See a YAML feed config example
channel:
  url: "http://domainname.tld/whatever.json"
  json: true
selectors:
  title:
    selector: "foo"

Set any HTTP header in the request

To set HTTP request headers, you can add them to the channel's headers hash. This is useful for APIs that require an Authorization header.

channel:
  url: "https://example.com/api/resource"
  headers:
    Authorization: "Bearer YOUR_TOKEN"
selectors:
  # ... omitted

Or for setting a User-Agent:

channel:
  url: "https://example.com"
  headers:
    User-Agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
selectors:
  # ... omitted

Usage with a YAML config file

This step is not required to work with this gem. If you're using html2rss-web and want to create your private feed configs, keep on reading!

First, create a YAML file, e.g. feeds.yml. This file will contain your global config and multiple feed configs under the key feeds.

Example:

headers:
  "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1"
feeds:
  myfeed:
    channel:
    selectors:
  myotherfeed:
    channel:
    selectors:

Your feed configs go below feeds. Everything else is part of the global config.

Find a full example of a feeds.yml at spec/feeds.test.yml.

Now you can build your feeds like this:

Build feeds in Ruby
require 'html2rss'

myfeed = Html2rss.feed_from_yaml_config('feeds.yml', 'myfeed')
myotherfeed = Html2rss.feed_from_yaml_config('feeds.yml', 'myotherfeed')
Build feeds on the command line
html2rss feed feeds.yml myfeed
html2rss feed feeds.yml myotherfeed

Display the RSS feed nicely in a web browser

To display RSS feeds nicely in a web browser, you can:

  • add a plain old CSS stylesheet, or
  • use XSLT (eXtensible Stylesheet Language Transformations).

A web browser will apply these stylesheets and show the contents as described.

In a CSS stylesheet, you'd use element selectors to apply styles.

If you want to do more, then you need to create a XSLT. XSLT allows you to use a HTML template and to freely design the information of the RSS, including using JavaScript and external resources.

You can add as many stylesheets and types as you like. Just add them to your global configuration.

Ruby: a stylesheet config example
config = Html2rss::Config.new(
  { channel: {}, selectors: {} }, # omitted
  {
    stylesheets: [
      {
        href: '/relative/base/path/to/style.xls',
        media: :all,
        type: 'text/xsl'
      },
      {
        href: 'http://example.com/rss.css',
        media: :all,
        type: 'text/css'
      }
    ]
  }
)

Html2rss.feed(config)
YAML: a stylesheet config example
stylesheets:
  - href: "/relative/base/path/to/style.xls"
    media: "all"
    type: "text/xsl"
  - href: "http://example.com/rss.css"
    media: "all"
    type: "text/css"
feeds:
  # ... omitted

Recommended further readings:

Gotchas and tips & tricks

  • Check that the channel URL does not redirect to a mobile page with a different markup structure.
  • Do not rely on your web browser's developer console. html2rss does not execute JavaScript.
  • Fiddling with curl and pup to find the selectors seems efficient (curl URL | pup).
  • CSS selectors are versatile. Here's an overview.

Contributing

  1. Fork it ( https://github.com/html2rss/html2rss/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

html2rss-web's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar gil-robot avatar gildesmarais avatar github-actions[bot] avatar mabeett avatar renovate-bot avatar renovate[bot] avatar snyk-bot avatar vvzvlad avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

html2rss-web's Issues

500 Internal Error // Faraday::ConnectionFailed

Hello, I recently cam across your project, while testing it out I'm having some issues. I created a folder with two files:

docker-compose.yml

version: "3"
services:
  html2rss-web:
    image: gilcreator/html2rss-web
    ports:
      - "3000:3000"
    volumes:
      - type: bind
        source: ./feeds.yml
        target: /app/config/feeds.yml
        read_only: true
    environment:
      - RACK_ENV=production
      - HEALTH_CHECK_USERNAME=health
      - HEALTH_CHECK_PASSWORD=please-set-YOUR-OWN-veeeeeery-l0ng-aNd-h4rd-to-gue55-Passw0rd!
     

and

feeds.yml

stylesheets:
  - href: "/rss.xsl"
    media: "all"
    type: "text/xsl"
headers:
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
feeds:
  # your custom feeds go here:
  example:
    channel:
      url: https://www.reuters.com/technology/
      language: en
      ttl: 360
      time_zone: UTC
    selectors:
      items:
        selector: '[class^="story-collection"] > li'
      title:
        selector: h3
      link:
        selector: a:first
        extractor: href
      description:
        selector: p

No matter which config example, it returns the same error (this is a screenshot when using 120 commits config):

image

These are the logs:

[+] Building 0.0s (0/0)                                                                                                                                                                                              
[+] Running 1/0
 ✔ Container feeds-html2rss-web-1  Created                                                                                                                                                                      0.0s 
Attaching to feeds-html2rss-web-1
feeds-html2rss-web-1  | [1] Puma starting in cluster mode...
feeds-html2rss-web-1  | [1] * Puma version: 6.4.0 (ruby 3.2.2-p53) ("The Eagle of Durango")
feeds-html2rss-web-1  | [1] *  Min threads: 5
feeds-html2rss-web-1  | [1] *  Max threads: 5
feeds-html2rss-web-1  | [1] *  Environment: production
feeds-html2rss-web-1  | [1] *   Master PID: 1
feeds-html2rss-web-1  | [1] *      Workers: 2
feeds-html2rss-web-1  | [1] *     Restarts: (✔) hot (✖) phased
feeds-html2rss-web-1  | [1] * Preloading application
feeds-html2rss-web-1  | [1] * Listening on http://0.0.0.0:3000
feeds-html2rss-web-1  | [1] Use Ctrl-C to stop
feeds-html2rss-web-1  | [1] - Worker 0 (PID: 7) booted in 0.0s, phase: 0
feeds-html2rss-web-1  | [1] - Worker 1 (PID: 9) booted in 0.0s, phase: 0
feeds-html2rss-web-1  | source=rack-timeout id=80dcab76-8dda-4ea9-9e18-82e536d4da82 timeout=15000ms state=ready at=info
feeds-html2rss-web-1  | source=rack-timeout id=80dcab76-8dda-4ea9-9e18-82e536d4da82 timeout=15000ms service=5605ms state=completed at=info

What could be the issue?

Make HealthCheck checks concurrently

The HealthChecks run sequentially. That works fine for one or two custom configs, but could become slow with more feeds.

HealthCheck.run should request feeds concurrently (e.g. using Ruby's Fiber or Ractor).

Add to snapcraft store

  • add .snapcraft.yml which runs this project as daemon
  • allow usage of a custom feeds.yml
  • run snap on ci and request a feed (similar to docker)
  • on master branch, push new snap version
  • add instructions to readme

Wrong result for different dynamic parameter value

I am using latest docker image with dynamic parameters for a feed and I see sometimes the resulf of one parameter given in the other one.

Here I attach a bash shell script with

  • a docker-compose sample project with a flask web application which gives a previsible result.
  • a loop asking html2css web different previsible results.

Briefly, when I run it I find a results like from the second query.
The output results just the first one repeated.

+ curl -s 'http://localhost:3001/failer.rss?id=1otherstring'
      <description>2023-04-16 15:34:23.958242 - foo random description</description>

while the output should be:

+ curl -s 'http://localhost:3001/failer.rss?id=1otherstring'
      <description>2023-04-16 15:34:23.958242 - 1otherstring random description</description>

Letme know if you need further information,
thanks in advance,

[ edit: WEB_MAX_THREADS=1, WEB_CONCURRENCY=1 ]

script launch

.  ./the_script_from_details.sh

Test Script:

#!/bin/bash
set -x

cd `mktemp -d`

mkdir -p templates/
cat <<EOF >app.py
from flask import Flask
from flask import render_template
from datetime import datetime
app = Flask(__name__)

@app.route('/')
@app.route('/<name>')
def hello(name=None):
    return render_template('hello.html', name=name, date=datetime.now())

if __name__ == '__main__':
        app.run(host='0.0.0.0', port=8000)
EOF

cat <<EOF >templates/hello.html
<!DOCTYPE html>
<html>
<head>
{% if name %}
<title>Title for {{ name }}</title>
{% else %}
<title>Title {{ name }}</title>
{% endif %}
</head>
<body>
  <div class="foo">
{% if name %}
  <h1><a href="https://google.com/search?q={{ date}}">Hello {{ name }}! at {{ date }}</a></h1>
  <div class="item">{{ date }} - {{ name }} random description</div>
{% else %}
  <h1>Hello, World!</h1>
  <div class="item">nada - nada random description</div>
{% endif %}
  </div>
</body>
</html>
EOF

cat <<'EOF' >Dockerfile 
FROM python:3.10-alpine AS builder
WORKDIR /app
RUN pip3 install Flask==2.2.3
RUN mkdir -p /app/templates
COPY . /app
ENTRYPOINT ["python3"]
CMD ["app.py"]
FROM builder as dev-envs
RUN \
  apk update && \
  apk add git
EOF

cat <<'EOF' >docker-compose.yml
version: "3.2"
services:
  web: 
    build:
      context: ./
    image: local/someflask
    stop_signal: SIGINT
    ports:
      - '8000:8000'
  html2rss-web:
    image: gilcreator/html2rss-web
    ports:
      - "3001:3000"
    volumes:
      - type: bind
        source: ./feeds.yml
        target: /app/config/feeds.yml
        read_only: true
    environment:
      - RACK_ENV=production
      - HEALTH_CHECK_USERNAME=health
      - HEALTH_CHECK_PASSWORD=please-set-YOUR-OWN-veeeeeery-l0ng-aNd-h4rd-to-gue55-Passw0rd 
      - WEB_MAX_THREADS=1
      - WEB_CONCURRENCY=1
EOF

cat <<'EOF' >feeds.yml
stylesheets:
  - href: "/rss.xsl"
    media: "all"
    type: "text/xsl"
headers:
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
feeds:
  failer:
    channel:
      url: http://web:8000/%<id>s
      title: Test web - %<id>s
      ttl: 120
    selectors:
      items:
        selector: "div.foo"
      title:
        selector: "h1"
      link:
        selector: "h1 > a"
        extractor: "href"
      description: 
        selector: "div.item"
EOF

docker-compose up --build -d 

while sleep 1; do curl -s http://localhost:3001/ >/dev/null && break ; done 

sleep 3 
curl -s http://localhost:3001/failer.rss?id=foo    | grep 'description' | tail -n 1
curl -s http://localhost:3001/failer.rss?id=foo    | grep 'description' | tail -n 1
for item in {1..10}
do
  curl -s http://localhost:3001/failer.rss?id=${item}otherstring | grep 'description' | tail -n 1
  sleep 10
done

ArgumentError when setting RACK_TIMEOUT_SERVICE_TIMEOUT envvar

If the environment variable RACK_TIMEOUT_SERVICE_TIMEOUT is set to any value, html2rss-web will fail with the following error:

Puma caught this error: value "0" should be false, zero, or a positive number. (ArgumentError)
/html2rss/vendor/bundle/ruby/3.1.0/gems/rack-timeout-0.6.3/lib/rack/timeout/core.rb:57:in read_timeout_property' /html2rss/vendor/bundle/ruby/3.1.0/gems/rack-timeout-0.6.3/lib/rack/timeout/core.rb:71:in initialize'
/html2rss/vendor/bundle/ruby/3.1.0/gems/roda-3.57.0/lib/roda.rb:393:in new' /html2rss/vendor/bundle/ruby/3.1.0/gems/roda-3.57.0/lib/roda.rb:393:in block in build_rack_app'
/html2rss/vendor/bundle/ruby/3.1.0/gems/roda-3.57.0/lib/roda.rb:391:in reverse_each' /html2rss/vendor/bundle/ruby/3.1.0/gems/roda-3.57.0/lib/roda.rb:391:in build_rack_app'
/html2rss/vendor/bundle/ruby/3.1.0/gems/roda-3.57.0/lib/roda.rb:34:in app' /html2rss/vendor/bundle/ruby/3.1.0/gems/roda-3.57.0/lib/roda.rb:53:in call'
/html2rss/vendor/bundle/ruby/3.1.0/gems/rack-unreloader-2.0.0/lib/rack/unreloader.rb:87:in call' /html2rss/vendor/bundle/ruby/3.1.0/gems/puma-5.6.4/lib/puma/configuration.rb:252:in call'
/html2rss/vendor/bundle/ruby/3.1.0/gems/puma-5.6.4/lib/puma/request.rb:77:in block in handle_request' /html2rss/vendor/bundle/ruby/3.1.0/gems/puma-5.6.4/lib/puma/thread_pool.rb:340:in with_force_shutdown'
/html2rss/vendor/bundle/ruby/3.1.0/gems/puma-5.6.4/lib/puma/request.rb:76:in handle_request' /html2rss/vendor/bundle/ruby/3.1.0/gems/puma-5.6.4/lib/puma/server.rb:441:in process_client'
/html2rss/vendor/bundle/ruby/3.1.0/gems/puma-5.6.4/lib/puma/thread_pool.rb:147:in `block in spawn_thread'

This issue is caused by line 19 of the app.rb retrieving the environment variable without converting it to integer or boolean, and then passing it over to Rack::Timeout:

use Rack::Timeout, service_timeout: ENV.fetch('RACK_TIMEOUT_SERVICE_TIMEOUT', 15)

A simple fix would be to replace line 19 with
use Rack::Timeout
This would leave the envvar parsing up to rack-timeout's initialization function. Also, the default timeout used by rack-timeout(15s) is the same as the one specified in line 19, so there's no need to re-define it.

feeds.yml not loaded using docker-compose.yml

I'm trying to run html2rss-web from docker using the docker-compose.yml provided, but when I open the web interface I just see the default example.rss, not mine.
image

There's not a lot of logging telling me what's going on, so this is also a feature request: display on startup the config that is loaded and how it is interpreted.

This is my feeds.yml, which is mounted to /app/config/feeds.yml. Could it be that this is not the correct location?

stylesheets:
  - href: "/rss.xsl"
    media: "all"
    type: "text/xsl"
headers:
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
feeds:
  # your custom feeds go here:
  samengezondindeventer:
    channel:
      url: https://samengezondindeventer.nl/nieuws
      title: "Samen gezond in Deventer"
      ttl: 120
    selectors:
      items:
        selector: "article"
      title:
        selector: "h2 a"
      link:
        selector: "a"
        extractor: "href"

Support for sub-path reverse proxy

Hi,

Is there a way to host this site under a sub-path reverse proxy? I mean something like https://nosuchdomain.invalid/html2rss, with an Nginx config like this:

upstream html2rss {
  server 127.0.0.1:3000;
}

server {
  # listen block and other sub-path sites would go here
  location /htm2rss/ {
    proxy_pass http://html2rss/;
  }
}

When I use the above Nginx site config, I'm able to download the XML files for the RSS feeds, but the browser preview does not work, since the html2rss-web site assumes that its asset files(like styles.css) are located at the root URL and does not add the /html2rss prefix.

Is there a configuration option for adding a prefix to the URLs of the site's assets? I could not find any myself...

In any case, thanks for the help and especially for this project, it's extremely useful! :)

Selectors

First, my compliments for the interesting project!

What I did:

  1. cloned html2rss-web repo
  2. built and ran container
  3. accessed rss feeds from html2rss-configs
  4. tried to generate my own feeds from .yml files and added a couple into config.yml

Basically, there are 4 main aspects of the problem:

  1. Seems, some selectors (e.g. "description") are causing "Internal Server Problem". Try "https://some.domain/webentwickler-jobs.de/in.rss"

  2. Other selectors are ignored e.g. "update". Basically, only "title" and "link" are displayed in rss feeds.

  3. If you "docker exec -it ..." into the container for generating feeds from .yml, you face the following problem:
    image

gem env:
image

bundler -v:
Bundler version 2.2.18

Gemfile.lock:
... BUNDLED WITH 2.2.17 ...

  1. /health_check.txt endpoint doesn't work returning "success" alongside with "Internal Server Problem"

Request proxy support

Some websites have strict anti-crawler policies and require the use of a proxy to access them normally.

Possible issue around caching on apnews.com

When attempting to use the new configuration in the following PR: html2rss/html2rss-configs#176 I seem to have hit an issue around the caching of dynamic config files. I have yet to figure out a good set of steps to reproduce, or find the root cause of where exactly it goes wrong. But what i have done is this:

Try to load section=trending-news then shortly after attempt to load another, for example section=ukraine. It will either mix the stories from both trending-news and ukraine. Or only load the previous trending-news news stories under ukraine.

My feeling is that it might have to do with these pages taking a bit to load, and there are errors seeming to be around timeouts. But this might be the wrong path to go down. You can see the logs below:

[1] Puma starting in cluster mode...
[1] * Puma version: 5.6.2 (ruby 3.1.1-p18) ("Birdie's Version")
[1] *  Min threads: 5
[1] *  Max threads: 5
[1] *  Environment: production
[1] *   Master PID: 1
[1] *      Workers: 2
[1] *     Restarts: (✔) hot (✖) phased
[1] * Preloading application
[1] * Listening on http://0.0.0.0:3000
[1] Use Ctrl-C to stop
[1] - Worker 0 (PID: 3) booted in 0.0s, phase: 0
[1] - Worker 1 (PID: 4) booted in 0.0s, phase: 0
source=rack-timeout id=0894f721-5348-4ba2-9fac-0fffcabb1078 timeout=15000ms state=ready at=info
/usr/local/bundle/bundler/gems/html2rss-a898923f92b2/lib/html2rss/item_extractors/href.rb:26: warning: redefining constant Struct::Options
/usr/local/bundle/bundler/gems/html2rss-a898923f92b2/lib/html2rss/item_extractors/html.rb:25: warning: redefining constant Struct::Options
/usr/local/bundle/bundler/gems/html2rss-a898923f92b2/lib/html2rss/item_extractors/static.rb:16: warning: redefining constant Struct::Options
/usr/local/bundle/bundler/gems/html2rss-a898923f92b2/lib/html2rss/item_extractors/text.rb:23: warning: redefining constant Struct::Options
source=rack-timeout id=0894f721-5348-4ba2-9fac-0fffcabb1078 timeout=15000ms service=1462ms state=completed at=info
source=rack-timeout id=45b4009a-7b73-4652-b7d2-fc2e84178fe1 timeout=15000ms state=ready at=info
source=rack-timeout id=45b4009a-7b73-4652-b7d2-fc2e84178fe1 timeout=15000ms service=1ms state=completed at=info
source=rack-timeout id=a2bd4d83-a7b9-420e-b131-668b5394abc3 timeout=15000ms state=ready at=info
source=rack-timeout id=a2bd4d83-a7b9-420e-b131-668b5394abc3 timeout=15000ms service=1ms state=completed at=info
source=rack-timeout id=1e97365c-5228-4d84-a3b2-c3b401cd06d5 timeout=15000ms state=ready at=info
source=rack-timeout id=1e97365c-5228-4d84-a3b2-c3b401cd06d5 timeout=15000ms service=4ms state=completed at=info
source=rack-timeout id=a2720804-beca-41de-9003-194396ef1a69 timeout=15000ms state=ready at=info
source=rack-timeout id=9f3a171e-3956-47fc-8eed-cd3fe10a51a0 timeout=15000ms state=ready at=info
source=rack-timeout id=a2720804-beca-41de-9003-194396ef1a69 timeout=15000ms service=2ms state=completed at=info
source=rack-timeout id=9f3a171e-3956-47fc-8eed-cd3fe10a51a0 timeout=15000ms service=1ms state=completed at=info
source=rack-timeout id=ad960dbb-d315-4752-8229-fc42159466d8 timeout=15000ms state=ready at=info
source=rack-timeout id=ad960dbb-d315-4752-8229-fc42159466d8 timeout=15000ms service=1ms state=completed at=info
source=rack-timeout id=806abc6b-43c8-4479-ba37-0ad93475f3a3 timeout=15000ms state=ready at=info
/usr/local/bundle/bundler/gems/html2rss-a898923f92b2/lib/html2rss/item_extractors/href.rb:26: warning: redefining constant Struct::Options
/usr/local/bundle/bundler/gems/html2rss-a898923f92b2/lib/html2rss/item_extractors/html.rb:25: warning: redefining constant Struct::Options
/usr/local/bundle/bundler/gems/html2rss-a898923f92b2/lib/html2rss/item_extractors/static.rb:16: warning: redefining constant Struct::Options
/usr/local/bundle/bundler/gems/html2rss-a898923f92b2/lib/html2rss/item_extractors/text.rb:23: warning: redefining constant Struct::Options
source=rack-timeout id=806abc6b-43c8-4479-ba37-0ad93475f3a3 timeout=15000ms service=4094ms state=completed at=info
source=rack-timeout id=2c4a2607-64e9-44ca-9732-bbaace89398b timeout=15000ms state=ready at=info
source=rack-timeout id=2c4a2607-64e9-44ca-9732-bbaace89398b timeout=15000ms service=634ms state=completed at=info
source=rack-timeout id=de17384a-22f5-4aac-8295-f79e2c6c5204 timeout=15000ms state=ready at=info
source=rack-timeout id=de17384a-22f5-4aac-8295-f79e2c6c5204 timeout=15000ms service=364ms state=completed at=info

Fetch full text by following the item URL?

When no description or text is available (only a heading and/or an image), is html2rss able to fetch the full text of an item by following the URL (load a new page), then selecting elements that contains the text, date, author etc – and add it to the generated RSS feed?

I have tried to read the available documentation but could not find such a feature described. It would be quite handy to have such a feature 😏 One example of a site where this would be handy: https://www.op.no/debatt/

Dependency Dashboard

This issue provides visibility into Renovate updates and their statuses. Learn more

This repository currently has no open or pending branches.


  • Check this box to trigger a request for Renovate to run again on this repository

html2rss-web with traefik: not proxying, container stuck in "starting"

Hallo

I am trying to use html2rss-web with Docker and Traefik.

My docker-compose.yml:

version: '3.3'
services:
  html2rss:
    image: gilcreator/html2rss-web
    container_name: html2rss                                                                                                                                                                                                
    volumes:
      - type: bind
        source: ./feeds.yml
        target: /app/config/feeds.yml
        read_only: true
    environment:
      - PORT=80
      - RACK_ENV=production
      - HEALTH_CHECK_USERNAME=health
      - HEALTH_CHECK_PASSWORD=xxx
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.html2rss.entrypoints=http"
      - "traefik.http.routers.html2rss.rule=Host(`html2rss.xxx.de`)"
      - "traefik.http.middlewares.html2rss-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.html2rss.middlewares=html2rss-https-redirect"
      - "traefik.http.routers.html2rss-secure.entrypoints=https"
      - "traefik.http.routers.html2rss-secure.rule=Host(`html2rss.xxx.de`)"
      - "traefik.http.routers.html2rss-secure.tls=true"
      - "traefik.http.routers.html2rss-secure.tls.certresolver=http"
      - "traefik.http.routers.html2rss-secure.service=html2rss"
      - "traefik.http.services.html2rss.loadbalancer.server.port=80"
      - "traefik.docker.network=proxy"
    networks:
      - proxy

networks:
  proxy:
    external: true

In Traefik's log I find

time="2023-12-22T20:29:48+01:00" level=debug msg="Filtering unhealthy or starting container" container=html2rss-html2rss-web-7e3d7a19bf11ae0876fd5848850fa3ddc638c59f11ccbaf8072734db5cbaa012 providerName=docker

Traefik's view is correct:

root# docker ps 
CONTAINER ID   IMAGE                             COMMAND                  CREATED         STATUS                            PORTS                                                                      NAMES
7e3d7a19bf11   gilcreator/html2rss-web           "bundle exec 'puma -…"   7 minutes ago   Up 7 minutes (health: starting)   3000/tcp                                                                   html2rss

How can I change the setup to have html2rss-web signal it is healthy?
I can access the container's web interface via the container IP on port 80.

Thanks
M

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.