Web

robots.txt

robots.txt read as Google does: whether an agent may fetch a path, its crawl delay and sitemaps; and your own site's robots.txt written.

Version 1.0.0 · 5 functions · 1 crate

#crawling#seo#bots#scraping

Functions

What use robots.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use robots_allowed, robots_check from robots (Quillo 0.6).

robots_allowed(robots_txt: str, user_agent: str, url: str) → boolor an error

Whether user_agent (your crawler's name, such as "QuilloBot") may fetch url (a full URL or a path) under these robots.txt rules: the longest matching rule wins, Allow on a tie, * and $ understood.

robots_check(robots_txt: str, user_agent: str, urls: list) → listor an error

Many URLs checked at once: [{ url, allowed }], in order. At most 100,000.

robots_info(robots_txt: str, user_agent: str) → anyor an error

What the file says beyond the rules: { crawl_delay, sitemaps }, the delay in seconds between requests for this agent (null when none is set).

robots_url(page_url: str) → stror an error

Where a page's robots.txt is: https://example.com/robots.txt for any URL of that site.

robots_write(groups: list, sitemaps: list) → stror an error

A robots.txt for your own site: groups is [{ agents: ["*"], allow: ["/"], disallow: ["/admin", "/cart"], crawl_delay: 2 }], sitemaps the sitemaps' full URLs.

Get it

$ quillo install robots               # robots.qwer into this folder$ quillo install robots --example     # and its example, robots.qwe

Or with curl:

$ curl -O https://quillolang.org/plugins/files/robots.qwer$ curl -O https://quillolang.org/plugins/files/robots.qwe

Then, in your program, all of it or only what you call:

main.qwe
use robots.qweruse robots_allowed, robots_check from robots      // Quillo 0.6: only these

It uses this crate, which cargo fetches the first time the plugin is built:

[dependencies]
texting_robots = "0.2"

Example

robots.qwe
// A link checker's politeness, and the site's own robots.txt: what a crawler may fetch under a// site's rules (here a sample file; a real crawler gets it with http.get(robots_url(page))).////   quillo run robots.qwe      then open http://localhost:8080/may?path=/shop/cartuse "robots.qwer"let RULES = `User-agent: *Disallow: /admin/Disallow: /shop/cartDisallow: /*.pdf$Allow: /admin/public/User-agent: QuilloBotDisallow: /drafts/Crawl-delay: 2Sitemap: https://shop.example.com/sitemap.xml`route GET /may ? { path: str, agent: str = "SomeBot" } = { path, agent, allowed: robots_allowed(RULES, agent, path)? }route GET /crawl = {    checks: robots_check(RULES, "SomeBot", ["/shop/shoes", "/shop/cart", "/admin/settings", "/admin/public/logo.png", "/files/price-list.pdf", "/files/price-list.pdf?v=2"])? | map((c) => `${c.allowed ? "fetch" : "skip "} ${c.url}`),    quillobot: robots_info(RULES, "QuilloBot")?,    robots_of: robots_url("https://shop.example.com/shop/shoes?color=red")?,}route GET /robots.txt = respond(200, robots_write([{ agents: ["*"], allow: ["/"], disallow: ["/admin", "/cart"] }, { agents: ["GPTBot", "CCBot"], disallow: ["/"] }], ["https://shop.example.com/sitemap.xml"])?, { "content-type": "text/plain" })
$ quillo run robots.qwe$ curl 'localhost:8080/may?path=/shop/cart'$ curl 'localhost:8080/crawl'$ curl 'localhost:8080/robots.txt'

Source

robots.qwer
//! robots.txt read as Google does: whether a user agent may fetch a path, its crawl delay and the sitemaps listed, for crawlers, link checkers and preview fetchers; and your own site's robots.txt written.//! version: 1.0.0//!//! [dependencies]//! texting_robots = "0.2"use serde_json::{json, Value};const MAX_TXT: usize = 500 * 1024;fn robot(txt: &str, agent: &str) -> Result<texting_robots::Robot, String> {    // Google reads the first 500 KiB of a robots.txt; so does this.    let mut end = txt.len().min(MAX_TXT);    while !txt.is_char_boundary(end) {        end -= 1;    }    texting_robots::Robot::new(agent, txt[..end].as_bytes()).map_err(|e| format!("robots.txt: {}", e))}/// Whether `user_agent` (your crawler's name, such as "QuilloBot") may fetch `url` (a full URL or a path) under these robots.txt rules: the longest matching rule wins, Allow on a tie, `*` and `$` understood.pub fn robots_allowed(robots_txt: &str, user_agent: &str, url: &str) -> Result<bool, String> {    Ok(robot(robots_txt, user_agent)?.allowed(url))}/// Many URLs checked at once: `[{ url, allowed }]`, in order. At most 100,000.pub fn robots_check(robots_txt: &str, user_agent: &str, urls: Vec<String>) -> Result<Vec<Value>, String> {    if urls.len() > 100_000 {        return Err("at most 100,000 URLs at once".into());    }    let r = robot(robots_txt, user_agent)?;    Ok(urls.iter().map(|u| json!({ "url": u, "allowed": r.allowed(u) })).collect())}/// What the file says beyond the rules: `{ crawl_delay, sitemaps }`, the delay in seconds between requests for this agent (null when none is set).pub fn robots_info(robots_txt: &str, user_agent: &str) -> Result<Value, String> {    let r = robot(robots_txt, user_agent)?;    Ok(json!({ "crawl_delay": r.delay.map(|d| d as f64), "sitemaps": r.sitemaps }))}/// Where a page's robots.txt is: `https://example.com/robots.txt` for any URL of that site.pub fn robots_url(page_url: &str) -> Result<String, String> {    texting_robots::get_robots_url(page_url).map_err(|e| format!("{}: {:?}", page_url, e))}/// A robots.txt for your own site: `groups` is `[{ agents: ["*"], allow: ["/"], disallow: ["/admin", "/cart"], crawl_delay: 2 }]`, `sitemaps` the sitemaps' full URLs.pub fn robots_write(groups: Vec<serde_json::Value>, sitemaps: Vec<String>) -> Result<String, String> {    let mut out = String::new();    let list = |g: &Value, k: &str| -> Vec<String> { g.get(k).and_then(Value::as_array).map(|a| a.iter().filter_map(Value::as_str).map(|s| s.replace(['\n', '\r'], "")).collect()).unwrap_or_default() };    for g in &groups {        let agents = list(g, "agents");        if agents.is_empty() {            return Err("each group names its `agents` (\"*\" for all)".into());        }        for a in &agents {            out.push_str(&format!("User-agent: {}\n", a));        }        for p in list(g, "allow") {            out.push_str(&format!("Allow: {}\n", p));        }        for p in list(g, "disallow") {            out.push_str(&format!("Disallow: {}\n", p));        }        if let Some(d) = g.get("crawl_delay").and_then(Value::as_f64) {            out.push_str(&format!("Crawl-delay: {}\n", d));        }        out.push('\n');    }    for s in sitemaps {        out.push_str(&format!("Sitemap: {}\n", s.replace(['\n', '\r'], "")));    }    Ok(out)}
Bots and crawlers bots.qwer · 1.0.0Crawlers told apart by User-Agent: search engines, AI training and answer bots, link previews, SEO tools, monitors and libraries, with their owner; a claimed Googlebot checked by reverse and forward DNS; and robots.txt that blocks chosen categories.botsrobotsaicrawling6 views · 11 downloadsSitemaps sitemap_read.qwer · 1.0.0Sitemaps and sitemap indexes read from XML, .xml.gz or text: URLs with lastmod, changefreq, priority and images; and a sitemap written for your pages.seocrawlingxmlsitemaps7 views · 8 downloadsStructured data structured_data.qwer · 1.0.0JSON-LD, microdata, Open Graph and Twitter tags read out of HTML; schema.org JSON-LD written for products, articles, breadcrumbs and FAQs; and items checked for what Google's rich results need.seohtmljsonscraping7 views · 8 downloadsScrape pages scrape.qwer · 1.0.0CSS selectors over HTML, a page's link preview (title, description, image) and its text without scripts.htmlscrapingpreviewsseo6 views · 7 downloadsURL tools url_tools.qwer · 1.0.0URLs by the rules browsers use: parts and query as a map, relative links resolved, a normal form for comparing, tracking parameters stripped, query values set.urlslinkstrackingprivacyseo7 views · 6 downloadsWeb app manifest pwa_manifest.qwer · 1.0.0Installable web apps: the manifest written with sensible defaults and checked against what browsers need for Install, the icon set (maskable, Apple's and favicons) made from one image, and the head tags.pwamobileimagesseo7 views · 6 downloads
Thread
87Useful? Like it, or add to its thread below.

Thread 0 posts

On robots.txt: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.