Skip to content

Commit 2915c3d

Browse files
committed
rdnl scraper
1 parent 8cfab2a commit 2915c3d

4 files changed

Lines changed: 186 additions & 0 deletions

File tree

lib/ingestors/ingestor_factory.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def self.taxila_ingestors
3636
Ingestors::Taxila::DccIngestor,
3737
Ingestors::Taxila::SenseIngestor,
3838
Ingestors::Taxila::VuMaterialIngestor,
39+
Ingestors::Taxila::RdnlIngestor,
3940
]
4041
end
4142

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
require 'open-uri'
2+
require 'csv'
3+
require 'nokogiri'
4+
5+
module Ingestors
6+
module Taxila
7+
class RdnlIngestor < Ingestor
8+
def self.config
9+
{
10+
key: 'rdnl_event',
11+
title: 'RDNL Events API',
12+
category: :events
13+
}
14+
end
15+
16+
def read(url)
17+
begin
18+
process_rdnl(url)
19+
rescue Exception => e
20+
@messages << "#{self.class.name} failed with: #{e.message}"
21+
end
22+
23+
# finished
24+
nil
25+
end
26+
27+
private
28+
29+
def process_rdnl(url)
30+
url = "https://researchdata.nl/agenda/"
31+
event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('main > article > .archive__grid > .column > .archive__content > .column')
32+
event_page.each do |event_data|
33+
event = OpenStruct.new
34+
35+
event.url = event_data.css('h2.card__title > a')[0].get_attribute('href')
36+
event.title = event_data.css('h2.card__title > a')[0].text.strip
37+
38+
start_str = event_data.css('dl.meta-list > div > dd')[0].text.strip.split('-')
39+
if start_str[1].include?(':')
40+
event.start = Time.zone.parse(start_str[0])
41+
event.end = Time.zone.parse(start_str[0]).beginning_of_day + Time.zone.parse(start_str[1]).seconds_since_midnight.seconds
42+
else
43+
event.start = Time.zone.parse(start_str[0])
44+
event.end = Time.zone.parse(start_str[1])
45+
end
46+
event.start = event.start.change(year: event.end.year) if event.start < event.end - 1.year
47+
event.start = event.start.change(year: event.end.year - 1) if event.start > event.end
48+
if event.start < Time.zone.now - 2.weeks
49+
event.start = event.start.change(year: Time.now.year + 1)
50+
event.end = event.end.change(year: Time.now.year + 1)
51+
end
52+
53+
event.venue = event_data.css('dl.meta-list > div > dd')[1].text.strip
54+
event.source = 'RDNL'
55+
event.timezone = 'Amsterdam'
56+
event.set_default_times
57+
puts event.title
58+
puts event.url
59+
puts event.start
60+
puts event.end
61+
puts event.venue
62+
63+
add_event(event)
64+
rescue Exception => e
65+
@messages << "Extract event fields failed with: #{e.message}"
66+
end
67+
end
68+
end
69+
end
70+
end
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
require 'test_helper'
2+
3+
class RDNLIngestorTest < ActiveSupport::TestCase
4+
setup do
5+
@user = users(:regular_user)
6+
@content_provider = content_providers(:another_portal_provider)
7+
mock_ingestions
8+
mock_timezone # System time zone should not affect test result
9+
end
10+
11+
teardown do
12+
reset_timezone
13+
end
14+
15+
test 'can ingest events from rdnl' do
16+
source = @content_provider.sources.build(
17+
url: 'https://.knaw.nl/en/agenda/?filter=true&page=',
18+
method: 'rdnl',
19+
enabled: true
20+
)
21+
22+
ingestor = Ingestors::Taxila::RdnlIngestor.new
23+
24+
# check event doesn't
25+
new_title = 'Essentials 4 Data Support, Feb/Mar 2026'
26+
new_url = 'https://researchdata.nl/agenda/essentials-4-data-support-feb-mar-2026/'
27+
refute Event.where(title: new_title, url: new_url).any?
28+
29+
# run task
30+
assert_difference 'Event.count', 1 do
31+
freeze_time(2025) do
32+
VCR.use_cassette('ingestors/rdnl') do
33+
ingestor.read(source.url)
34+
ingestor.write(@user, @content_provider)
35+
end
36+
end
37+
end
38+
39+
assert_equal 1, ingestor.events.count
40+
assert ingestor.materials.empty?
41+
assert_equal 1, ingestor.stats[:events][:added]
42+
assert_equal 0, ingestor.stats[:events][:updated]
43+
assert_equal 0, ingestor.stats[:events][:rejected]
44+
45+
# check event does exist
46+
event = Event.where(title: new_title, url: new_url).first
47+
assert event
48+
assert_equal new_title, event.title
49+
assert_equal new_url, event.url
50+
51+
# check other fields
52+
assert_equal 'RDNL', event.source
53+
assert_equal 'Amsterdam', event.timezone
54+
assert_equal 'DANS-KNAW', event.venue
55+
assert_equal Time.zone.parse('Thu, 5 Feb 2026 09:00:00.000000000 UTC +00:00'), event.start
56+
assert_equal Time.zone.parse('Mon, 26 Mar 2026 17:00:00.000000000 UTC +00:00'), event.end
57+
end
58+
end

test/vcr_cassettes/ingestors/rdnl.yml

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)