mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-02 16:38:14 +00:00
Kotaku + Gizmodo RSS indexers
This commit is contained in:
1 parent
2c86a4189c
commit
6d082f2b9e
5 files changed
+156
-4
No files matched your search
@@ -0,0 +1,65 @@
|
||||
use crate::payloads::web_scraping_target::WebScrapingTarget;
|
||||
use enums::common::sqlite::skip_reason::SkipReason;
|
||||
use enums::common::sqlite::web_content_type::WebContentType;
|
||||
use errors::AnyhowResult;
|
||||
use log::warn;
|
||||
use rss::Channel;
|
||||
|
||||
const GIZMODO_RSS : &'static str = "kotaku_indexer.rs";
|
||||
|
||||
// TODO: Rename foo_feed() or foo_rss(), etc.
|
||||
pub async fn gizmodo_indexer() -> AnyhowResult<Vec<WebScrapingTarget>> {
|
||||
let content = reqwest::get(GIZMODO_RSS)
|
||||
.await?
|
||||
.bytes()
|
||||
.await?;
|
||||
|
||||
let channel = Channel::read_from(&content[..])?;
|
||||
|
||||
let mut targets = Vec::with_capacity(channel.items.len());
|
||||
|
||||
for item in channel.items {
|
||||
let canonical_url = match item.link {
|
||||
Some(url) => url.clone(),
|
||||
None => {
|
||||
warn!("Skipping item due to not having a URL");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let mut maybe_skip_reason = None;
|
||||
|
||||
//// Lazy heuristic to skip CNN video articles, which contain little text.
|
||||
//// eg. https://www.cnn.com/videos/politics/2023/02/08/pelosi-gop-hecklers-reaction-joe-biden-state-of-the-union-tapper-intv-vpx.cnn
|
||||
//if canonical_url.contains("/videos/") {
|
||||
// maybe_skip_reason = Some(SkipReason::VideoContent);
|
||||
//}
|
||||
|
||||
// NB: I'm not using these as I had anticipated.
|
||||
let maybe_image_url = None;
|
||||
|
||||
//let maybe_image_url = item.extensions.get("media")
|
||||
// .map(|media| media.get("group"))
|
||||
// .flatten()
|
||||
// .map(|group| group.get(0))
|
||||
// .flatten()
|
||||
// .map(|extension| extension.children.get("content"))
|
||||
// .flatten()
|
||||
// .map(|extensions| extensions.get(0)) // NB: First image is biggest
|
||||
// .flatten()
|
||||
// .map(|extension| extension.attrs.get("url"))
|
||||
// .flatten()
|
||||
// .map(|url| url.to_string());
|
||||
|
||||
targets.push(WebScrapingTarget {
|
||||
canonical_url,
|
||||
web_content_type: WebContentType::GizmodoArticle,
|
||||
maybe_title: item.title.clone(),
|
||||
maybe_full_image_url: maybe_image_url,
|
||||
maybe_thumbnail_image_url: None,
|
||||
maybe_skip_reason,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(targets)
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
pub mod gizmodo_article_scraper;
|
||||
pub mod gizmodo_article_scraper;
|
||||
pub mod gizmodo_indexer;
|
||||
@@ -0,0 +1,65 @@
|
||||
use crate::payloads::web_scraping_target::WebScrapingTarget;
|
||||
use enums::common::sqlite::skip_reason::SkipReason;
|
||||
use enums::common::sqlite::web_content_type::WebContentType;
|
||||
use errors::AnyhowResult;
|
||||
use log::warn;
|
||||
use rss::Channel;
|
||||
|
||||
const KOTAKU_RSS: &'static str = "https://kotaku.com/rss";
|
||||
|
||||
// TODO: Rename foo_feed() or foo_rss(), etc.
|
||||
pub async fn kotaku_indexer() -> AnyhowResult<Vec<WebScrapingTarget>> {
|
||||
let content = reqwest::get(KOTAKU_RSS)
|
||||
.await?
|
||||
.bytes()
|
||||
.await?;
|
||||
|
||||
let channel = Channel::read_from(&content[..])?;
|
||||
|
||||
let mut targets = Vec::with_capacity(channel.items.len());
|
||||
|
||||
for item in channel.items {
|
||||
let canonical_url = match item.link {
|
||||
Some(url) => url.clone(),
|
||||
None => {
|
||||
warn!("Skipping item due to not having a URL");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let mut maybe_skip_reason = None;
|
||||
|
||||
//// Lazy heuristic to skip CNN video articles, which contain little text.
|
||||
//// eg. https://www.cnn.com/videos/politics/2023/02/08/pelosi-gop-hecklers-reaction-joe-biden-state-of-the-union-tapper-intv-vpx.cnn
|
||||
//if canonical_url.contains("/videos/") {
|
||||
// maybe_skip_reason = Some(SkipReason::VideoContent);
|
||||
//}
|
||||
|
||||
// NB: I'm not using these as I had anticipated.
|
||||
let maybe_image_url = None;
|
||||
|
||||
//let maybe_image_url = item.extensions.get("media")
|
||||
// .map(|media| media.get("group"))
|
||||
// .flatten()
|
||||
// .map(|group| group.get(0))
|
||||
// .flatten()
|
||||
// .map(|extension| extension.children.get("content"))
|
||||
// .flatten()
|
||||
// .map(|extensions| extensions.get(0)) // NB: First image is biggest
|
||||
// .flatten()
|
||||
// .map(|extension| extension.attrs.get("url"))
|
||||
// .flatten()
|
||||
// .map(|url| url.to_string());
|
||||
|
||||
targets.push(WebScrapingTarget {
|
||||
canonical_url,
|
||||
web_content_type: WebContentType::KotakuArticle,
|
||||
maybe_title: item.title.clone(),
|
||||
maybe_full_image_url: maybe_image_url,
|
||||
maybe_thumbnail_image_url: None,
|
||||
maybe_skip_reason,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(targets)
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
pub mod kotaku_article_scraper;
|
||||
pub mod kotaku_article_scraper;
|
||||
pub mod kotaku_indexer;
|
||||
@@ -11,6 +11,8 @@ use strum::IntoEnumIterator;
|
||||
use web_scrapers::payloads::web_scraping_result::ScrapedWebArticle;
|
||||
use web_scrapers::payloads::web_scraping_target::WebScrapingTarget;
|
||||
use web_scrapers::sites::cnn::cnn_indexer::{cnn_indexer, CnnFeed};
|
||||
use web_scrapers::sites::gizmodo::gizmodo_indexer::gizmodo_indexer;
|
||||
use web_scrapers::sites::kotaku::kotaku_indexer::kotaku_indexer;
|
||||
use web_scrapers::sites::techcrunch::techcrunch_indexer::{techcrunch_indexer, TechcrunchFeed};
|
||||
|
||||
/// Download RSS feeds and index pages to determine which articles and content will be scraped (async/downstream of this)
|
||||
@@ -37,24 +39,42 @@ pub async fn web_index_ingestion_main_loop(job_state: Arc<JobState>) {
|
||||
|
||||
async fn single_iteration(job_state: &Arc<JobState>) -> AnyhowResult<()> {
|
||||
|
||||
// Kotaku
|
||||
{
|
||||
let index_targets = kotaku_indexer().await?;
|
||||
insert_targets(job_state, &index_targets).await?;
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
}
|
||||
|
||||
// Gizmodo
|
||||
{
|
||||
let index_targets = gizmodo_indexer().await?;
|
||||
insert_targets(job_state, &index_targets).await?;
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
}
|
||||
|
||||
// CNN
|
||||
for variant in CnnFeed::iter() {
|
||||
let index_targets = cnn_indexer(variant).await?;
|
||||
insert_targets(job_state, &index_targets).await?;
|
||||
thread::sleep(Duration::from_secs(5));
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
}
|
||||
|
||||
// TechCrunch
|
||||
for variant in TechcrunchFeed::iter() {
|
||||
let index_targets = techcrunch_indexer(variant).await?;
|
||||
insert_targets(job_state, &index_targets).await?;
|
||||
thread::sleep(Duration::from_secs(5));
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn insert_targets(job_state: &Arc<JobState>, targets: &Vec<WebScrapingTarget>) -> AnyhowResult<()> {
|
||||
while job_state.app_control_state.is_scraping_paused() {
|
||||
thread::sleep(Duration::from_secs(5));
|
||||
}
|
||||
|
||||
for target in targets.iter() {
|
||||
let _r = insert_web_scraping_target(Args {
|
||||
canonical_url: &target.canonical_url,
|
||||
|
||||
Reference in new issue
Block a user