mirror of
https://codeberg.org/gigirassy/blogfetch
synced 2026-08-30 15:27:41 +00:00
init
This commit is contained in:
+164
@@ -0,0 +1,164 @@
|
|||||||
|
#!/usr/bin/env crystal
|
||||||
|
|
||||||
|
require "http/client"
|
||||||
|
require "uri"
|
||||||
|
require "set"
|
||||||
|
|
||||||
|
USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:154.0) Gecko/20100101 Firefox/154.0"
|
||||||
|
MAX_BLOGS = 5000
|
||||||
|
|
||||||
|
def fetch(url : String) : String?
|
||||||
|
begin
|
||||||
|
response = HTTP::Client.get(
|
||||||
|
url,
|
||||||
|
headers: HTTP::Headers{
|
||||||
|
"User-Agent" => USER_AGENT,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil unless response.success?
|
||||||
|
|
||||||
|
response.body
|
||||||
|
rescue
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def blogspot_host(url : String) : String?
|
||||||
|
begin
|
||||||
|
host = URI.parse(url).host
|
||||||
|
return nil unless host
|
||||||
|
|
||||||
|
host = host.downcase
|
||||||
|
|
||||||
|
blogspot_domains = [
|
||||||
|
"blogspot.com",
|
||||||
|
"blogspot.co.uk",
|
||||||
|
"blogspot.de",
|
||||||
|
"blogspot.fr",
|
||||||
|
"blogspot.ca",
|
||||||
|
"blogspot.com.au",
|
||||||
|
"blogspot.in",
|
||||||
|
"blogspot.it",
|
||||||
|
"blogspot.nl",
|
||||||
|
"blogspot.es",
|
||||||
|
]
|
||||||
|
|
||||||
|
blogspot_domains.each do |domain|
|
||||||
|
if host == domain || host.ends_with?(".#{domain}")
|
||||||
|
return host
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
nil
|
||||||
|
rescue
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def blog_root(url : String) : String?
|
||||||
|
host = blogspot_host(url)
|
||||||
|
return nil unless host
|
||||||
|
|
||||||
|
"https://#{host}/"
|
||||||
|
end
|
||||||
|
|
||||||
|
def make_absolute(href : String, base : URI) : String?
|
||||||
|
href = href.strip
|
||||||
|
|
||||||
|
return nil if href.empty?
|
||||||
|
return nil if href.starts_with?("#")
|
||||||
|
return nil if href.starts_with?("javascript:")
|
||||||
|
return nil if href.starts_with?("mailto:")
|
||||||
|
return nil if href.starts_with?("tel:")
|
||||||
|
return nil if href.starts_with?("data:")
|
||||||
|
|
||||||
|
begin
|
||||||
|
uri = URI.parse(href)
|
||||||
|
|
||||||
|
if uri.scheme && uri.host
|
||||||
|
return href
|
||||||
|
end
|
||||||
|
|
||||||
|
host = base.host
|
||||||
|
return nil unless host
|
||||||
|
|
||||||
|
scheme = base.scheme || "https"
|
||||||
|
|
||||||
|
if href.starts_with?("/")
|
||||||
|
return "#{scheme}://#{host}#{href}"
|
||||||
|
end
|
||||||
|
|
||||||
|
base_path = base.path
|
||||||
|
base_path = "/" if base_path.nil? || base_path.empty?
|
||||||
|
|
||||||
|
directory =
|
||||||
|
if base_path.ends_with?("/")
|
||||||
|
base_path
|
||||||
|
else
|
||||||
|
base_path.sub(/\/[^\/]*$/, "/")
|
||||||
|
end
|
||||||
|
|
||||||
|
"#{scheme}://#{host}#{directory}#{href}"
|
||||||
|
rescue
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract_blog_roots(html : String, page_url : String) : Array(String)
|
||||||
|
results = Set(String).new
|
||||||
|
base = URI.parse(page_url)
|
||||||
|
|
||||||
|
html.scan(/<a\b[^>]*\bhref\s*=\s*["']([^"']+)["']/im) do |match|
|
||||||
|
href = match[1]
|
||||||
|
|
||||||
|
if absolute = make_absolute(href, base)
|
||||||
|
if root = blog_root(absolute)
|
||||||
|
results << root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
results.to_a
|
||||||
|
end
|
||||||
|
|
||||||
|
def crawl(start_urls : Array(String))
|
||||||
|
queue = Array(String).new
|
||||||
|
discovered = Set(String).new
|
||||||
|
crawled = Set(String).new
|
||||||
|
|
||||||
|
start_urls.each do |url|
|
||||||
|
if root = blog_root(url)
|
||||||
|
unless discovered.includes?(root)
|
||||||
|
discovered << root
|
||||||
|
queue << root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
while !queue.empty? && crawled.size < MAX_BLOGS
|
||||||
|
root = queue.shift
|
||||||
|
|
||||||
|
next if crawled.includes?(root)
|
||||||
|
|
||||||
|
crawled << root
|
||||||
|
|
||||||
|
puts root
|
||||||
|
|
||||||
|
html = fetch(root)
|
||||||
|
next unless html
|
||||||
|
|
||||||
|
extract_blog_roots(html, root).each do |new_root|
|
||||||
|
next if discovered.includes?(new_root)
|
||||||
|
|
||||||
|
discovered << new_root
|
||||||
|
queue << new_root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ARGV.empty?
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
|
crawl(ARGV.to_a)
|
||||||
Reference in New Issue
Block a user