diff --git a/dist/mercury.js b/dist/mercury.js index e075d92a..10b0b9fb 100644 --- a/dist/mercury.js +++ b/dist/mercury.js @@ -10,10 +10,10 @@ var cheerio = _interopDefault(require('cheerio')); var _Promise = _interopDefault(require('babel-runtime/core-js/promise')); var request = _interopDefault(require('request')); var _Reflect$ownKeys = _interopDefault(require('babel-runtime/core-js/reflect/own-keys')); +var _toConsumableArray = _interopDefault(require('babel-runtime/helpers/toConsumableArray')); var _slicedToArray = _interopDefault(require('babel-runtime/helpers/slicedToArray')); var stringDirection = _interopDefault(require('string-direction')); var _getIterator = _interopDefault(require('babel-runtime/core-js/get-iterator')); -var _toConsumableArray = _interopDefault(require('babel-runtime/helpers/toConsumableArray')); var _defineProperty = _interopDefault(require('babel-runtime/helpers/defineProperty')); var _typeof = _interopDefault(require('babel-runtime/helpers/typeof')); var validUrl = _interopDefault(require('valid-url')); @@ -348,6 +348,17 @@ var Resource = { } }; +var merge = function merge(extractor, domains) { + return domains.reduce(function (acc, domain) { + acc[domain] = extractor; + return acc; + }, {}); +}; + +function mergeSupportedDomains(extractor) { + return extractor.supportedDomains ? merge(extractor, [extractor.domain].concat(_toConsumableArray(extractor.supportedDomains))) : merge(extractor, [extractor.domain]); +} + var NYMagExtractor = { domain: 'nymag.com', content: { @@ -936,6 +947,9 @@ var PoliticoExtractor = { var DeadspinExtractor = { domain: 'deadspin.com', + + supportedDomains: ['jezebel.com', 'lifehacker.com', 'kotaku.com', 'gizmodo.com', 'jalopnik.com', 'kinja.com'], + title: { selectors: ['h1.headline'] }, @@ -1101,6 +1115,9 @@ var ApartmentTherapyExtractor = { var MediumExtractor = { domain: 'medium.com', + + supportedDomains: ['trackchanges.postlight.com'], + title: { selectors: ['h1'] }, @@ -1169,7 +1186,7 @@ var MediumExtractor = { } }; -var Extractors = { +var Extractors = _extends({ 'nymag.com': NYMagExtractor, 'blogspot.com': BloggerExtractor, 'wikipedia.org': WikipediaExtractor, @@ -1183,17 +1200,11 @@ var Extractors = { 'www.buzzfeed.com': BuzzfeedExtractor, 'fandom.wikia.com': WikiaExtractor, 'www.littlethings.com': LittleThingsExtractor, - 'www.politico.com': PoliticoExtractor, - 'deadspin.com': DeadspinExtractor, - 'jezebel.com': DeadspinExtractor, - 'lifehacker.com': DeadspinExtractor, - 'kotaku.com': DeadspinExtractor, - 'gizmodo.com': DeadspinExtractor, - 'jalopnik.com': DeadspinExtractor, + 'www.politico.com': PoliticoExtractor +}, mergeSupportedDomains(DeadspinExtractor), { 'www.broadwayworld.com': BroadwayWorldExtractor, - 'www.apartmenttherapy.com': ApartmentTherapyExtractor, - 'medium.com': MediumExtractor -}; + 'www.apartmenttherapy.com': ApartmentTherapyExtractor +}, mergeSupportedDomains(MediumExtractor)); // Spacer images to be removed var SPACER_RE = new RegExp('trans|transparent|spacer|blank', 'i'); diff --git a/dist/mercury.js.map b/dist/mercury.js.map index dd6e5d09..84acadc2 100644 --- a/dist/mercury.js.map +++ b/dist/mercury.js.map @@ -1 +1 @@ -{"version":3,"file":null,"sources":["../src/utils/range.js","../src/utils/validate-url.js","../src/utils/errors.js","../src/resource/utils/constants.js","../src/resource/utils/fetch-resource.js","../src/resource/utils/dom/normalize-meta-tags.js","../src/resource/utils/dom/constants.js","../src/resource/utils/dom/convert-lazy-loaded-images.js","../src/resource/utils/dom/clean.js","../src/resource/index.js","../src/extractors/custom/nymag.com/index.js","../src/extractors/custom/blogspot.com/index.js","../src/extractors/custom/wikipedia.org/index.js","../src/extractors/custom/twitter.com/index.js","../src/extractors/custom/www.nytimes.com/index.js","../src/extractors/custom/www.theatlantic.com/index.js","../src/extractors/custom/www.newyorker.com/index.js","../src/extractors/custom/www.wired.com/index.js","../src/extractors/custom/www.msn.com/index.js","../src/extractors/custom/www.yahoo.com/index.js","../src/extractors/custom/www.buzzfeed.com/index.js","../src/extractors/custom/fandom.wikia.com/index.js","../src/extractors/custom/www.littlethings.com/index.js","../src/extractors/custom/www.politico.com/index.js","../src/extractors/custom/deadspin.com/index.js","../src/extractors/custom/www.broadwayworld.com/index.js","../src/extractors/custom/www.apartmenttherapy.com/index.js","../src/extractors/custom/medium.com/index.js","../src/extractors/all.js","../src/utils/dom/constants.js","../src/utils/dom/strip-unlikely-candidates.js","../src/utils/dom/brs-to-ps.js","../src/utils/dom/paragraphize.js","../src/utils/dom/convert-to-paragraphs.js","../src/utils/dom/convert-node-to.js","../src/utils/dom/clean-images.js","../src/utils/dom/mark-to-keep.js","../src/utils/dom/strip-junk-tags.js","../src/utils/dom/clean-h-ones.js","../src/utils/dom/clean-attributes.js","../src/utils/dom/remove-empty.js","../src/extractors/generic/content/scoring/constants.js","../src/extractors/generic/content/scoring/get-weight.js","../src/extractors/generic/content/scoring/get-score.js","../src/extractors/generic/content/scoring/score-commas.js","../src/extractors/generic/content/scoring/score-length.js","../src/extractors/generic/content/scoring/score-paragraph.js","../src/extractors/generic/content/scoring/set-score.js","../src/extractors/generic/content/scoring/add-score.js","../src/extractors/generic/content/scoring/add-to-parent.js","../src/extractors/generic/content/scoring/get-or-init-score.js","../src/extractors/generic/content/scoring/score-node.js","../src/extractors/generic/content/scoring/score-content.js","../src/utils/text/normalize-spaces.js","../src/utils/text/extract-from-url.js","../src/utils/text/constants.js","../src/utils/text/page-num-from-url.js","../src/utils/text/remove-anchor.js","../src/utils/text/article-base-url.js","../src/utils/text/has-sentence-end.js","../src/utils/text/excerpt-content.js","../src/extractors/generic/content/scoring/merge-siblings.js","../src/extractors/generic/content/scoring/find-top-candidate.js","../src/utils/dom/clean-tags.js","../src/utils/dom/clean-headers.js","../src/utils/dom/rewrite-top-level.js","../src/utils/dom/make-links-absolute.js","../src/utils/dom/link-density.js","../src/utils/dom/extract-from-meta.js","../src/utils/dom/extract-from-selectors.js","../src/utils/dom/strip-tags.js","../src/utils/dom/within-comment.js","../src/utils/dom/node-is-sufficient.js","../src/utils/dom/is-wordpress.js","../src/cleaners/constants.js","../src/cleaners/author.js","../src/cleaners/lead-image-url.js","../src/cleaners/dek.js","../src/cleaners/date-published.js","../src/cleaners/content.js","../src/cleaners/title.js","../src/cleaners/resolve-split-title.js","../src/cleaners/index.js","../src/extractors/generic/content/extract-best-node.js","../src/extractors/generic/content/extractor.js","../src/extractors/generic/title/constants.js","../src/extractors/generic/title/extractor.js","../src/extractors/generic/author/constants.js","../src/extractors/generic/author/extractor.js","../src/extractors/generic/date-published/constants.js","../src/extractors/generic/date-published/extractor.js","../src/extractors/generic/dek/extractor.js","../src/extractors/generic/lead-image-url/constants.js","../src/extractors/generic/lead-image-url/score-image.js","../src/extractors/generic/lead-image-url/extractor.js","../src/extractors/generic/next-page-url/scoring/utils/score-similarity.js","../src/extractors/generic/next-page-url/scoring/utils/score-link-text.js","../src/extractors/generic/next-page-url/scoring/utils/score-page-in-link.js","../src/extractors/generic/next-page-url/scoring/constants.js","../src/extractors/generic/next-page-url/scoring/utils/score-extraneous-links.js","../src/extractors/generic/next-page-url/scoring/utils/score-by-parents.js","../src/extractors/generic/next-page-url/scoring/utils/score-prev-link.js","../src/extractors/generic/next-page-url/scoring/utils/should-score.js","../src/extractors/generic/next-page-url/scoring/utils/score-base-url.js","../src/extractors/generic/next-page-url/scoring/utils/score-next-link-text.js","../src/extractors/generic/next-page-url/scoring/utils/score-cap-links.js","../src/extractors/generic/next-page-url/scoring/score-links.js","../src/extractors/generic/next-page-url/extractor.js","../src/extractors/generic/url/constants.js","../src/extractors/generic/url/extractor.js","../src/extractors/generic/excerpt/constants.js","../src/extractors/generic/excerpt/extractor.js","../src/extractors/generic/word-count/extractor.js","../src/extractors/generic/index.js","../src/extractors/get-extractor.js","../src/extractors/root-extractor.js","../src/extractors/collect-all-pages.js","../src/mercury.js"],"sourcesContent":["export default function* range(start = 1, end = 1) {\n while (start <= end) {\n yield start += 1;\n }\n}\n","// extremely simple url validation as a first step\nexport default function validateUrl({ hostname }) {\n // If this isn't a valid url, return an error message\n return !!hostname;\n}\n","const Errors = {\n badUrl: {\n error: true,\n messages: 'The url parameter passed does not look like a valid URL. Please check your data and try again.',\n },\n};\n\nexport default Errors;\n","export const REQUEST_HEADERS = {\n 'User-Agent': 'Readability - http://readability.com/about/',\n};\n\n// The number of milliseconds to attempt to fetch a resource before timing out.\nexport const FETCH_TIMEOUT = 10000;\n\n// Content types that we do not extract content from\nconst BAD_CONTENT_TYPES = [\n 'audio/mpeg',\n 'image/gif',\n 'image/jpeg',\n 'image/jpg',\n];\n\nexport const BAD_CONTENT_TYPES_RE = new RegExp(`^(${BAD_CONTENT_TYPES.join('|')})$`, 'i');\n\n\n// Use this setting as the maximum size an article can be\n// for us to attempt parsing. Defaults to 5 MB.\nexport const MAX_CONTENT_LENGTH = 5242880;\n\n// Turn the global proxy on or off\n// Proxying is not currently enabled in Python source\n// so not implementing logic in port.\nexport const PROXY_DOMAINS = false;\nexport const REQUESTS_PROXIES = {\n http: 'http://38.98.105.139:33333',\n https: 'http://38.98.105.139:33333',\n};\n\nexport const DOMAINS_TO_PROXY = [\n 'nih.gov',\n 'gutenberg.org',\n];\n","import URL from 'url';\nimport request from 'request';\nimport { Errors } from 'utils';\n\nimport {\n REQUEST_HEADERS,\n FETCH_TIMEOUT,\n BAD_CONTENT_TYPES_RE,\n MAX_CONTENT_LENGTH,\n} from './constants';\n\nfunction get(options) {\n return new Promise((resolve, reject) => {\n request(options, (err, response, body) => {\n if (err) {\n reject(err);\n } else {\n resolve({ body, response });\n }\n });\n });\n}\n\n// Evaluate a response to ensure it's something we should be keeping.\n// This does not validate in the sense of a response being 200 level or\n// not. Validation here means that we haven't found reason to bail from\n// further processing of this url.\n\nexport function validateResponse(response, parseNon2xx = false) {\n // Check if we got a valid status code\n if (response.statusMessage !== 'OK') {\n if (!response.statusCode) {\n throw new Error(\n `Unable to fetch content. Original exception was ${response.error}`\n );\n } else if (!parseNon2xx) {\n throw new Error(\n `Resource returned a response status code of ${response.statusCode} and resource was instructed to reject non-2xx level status codes.`\n );\n }\n }\n\n const {\n 'content-type': contentType,\n 'content-length': contentLength,\n } = response.headers;\n\n // Check that the content is not in BAD_CONTENT_TYPES\n if (BAD_CONTENT_TYPES_RE.test(contentType)) {\n throw new Error(\n `Content-type for this resource was ${contentType} and is not allowed.`\n );\n }\n\n // Check that the content length is below maximum\n if (contentLength > MAX_CONTENT_LENGTH) {\n throw new Error(\n `Content for this resource was too large. Maximum content length is ${MAX_CONTENT_LENGTH}.`\n );\n }\n\n return true;\n}\n\n// Grabs the last two pieces of the URL and joins them back together\n// This is to get the 'livejournal.com' from 'erotictrains.livejournal.com'\nexport function baseDomain({ host }) {\n return host.split('.').slice(-2).join('.');\n}\n\n// Set our response attribute to the result of fetching our URL.\n// TODO: This should gracefully handle timeouts and raise the\n// proper exceptions on the many failure cases of HTTP.\n// TODO: Ensure we are not fetching something enormous. Always return\n// unicode content for HTML, with charset conversion.\n\nexport default async function fetchResource(url, parsedUrl) {\n parsedUrl = parsedUrl || URL.parse(encodeURI(url));\n\n const options = {\n url: parsedUrl,\n headers: { ...REQUEST_HEADERS },\n timeout: FETCH_TIMEOUT,\n // Don't set encoding; fixes issues\n // w/gzipped responses\n encoding: null,\n // Accept cookies\n jar: true,\n // Accept and decode gzip\n gzip: true,\n // Follow any redirect\n followAllRedirects: true,\n };\n\n const { response, body } = await get(options);\n\n try {\n validateResponse(response);\n return { body, response };\n } catch (e) {\n return Errors.badUrl;\n }\n}\n","function convertMetaProp($, from, to) {\n $(`meta[${from}]`).each((_, node) => {\n const $node = $(node);\n\n const value = $node.attr(from);\n $node.attr(to, value);\n $node.removeAttr(from);\n });\n\n return $;\n}\n\n// For ease of use in extracting from meta tags,\n// replace the \"content\" attribute on meta tags with the\n// \"value\" attribute.\n//\n// In addition, normalize 'property' attributes to 'name' for ease of\n// querying later. See, e.g., og or twitter meta tags.\n\nexport default function normalizeMetaTags($) {\n $ = convertMetaProp($, 'content', 'value');\n $ = convertMetaProp($, 'property', 'name');\n return $;\n}\n","export const IS_LINK = new RegExp('https?://', 'i');\nexport const IS_IMAGE = new RegExp('.(png|gif|jpe?g)', 'i');\n\nexport const TAGS_TO_REMOVE = [\n 'script',\n 'style',\n 'form',\n].join(',');\n","import {\n IS_LINK,\n IS_IMAGE,\n} from './constants';\n\n// Convert all instances of images with potentially\n// lazy loaded images into normal images.\n// Many sites will have img tags with no source, or an image tag with a src\n// attribute that a is a placeholer. We need to be able to properly fill in\n// the src attribute so the images are no longer lazy loaded.\nexport default function convertLazyLoadedImages($) {\n $('img').each((_, img) => {\n Reflect.ownKeys(img.attribs).forEach((attr) => {\n const value = img.attribs[attr];\n\n if (attr !== 'src' && IS_LINK.test(value) &&\n IS_IMAGE.test(value)) {\n $(img).attr('src', value);\n }\n });\n });\n\n return $;\n}\n","import { TAGS_TO_REMOVE } from './constants';\n\nfunction isComment(index, node) {\n return node.type === 'comment';\n}\n\nfunction cleanComments($) {\n $.root().find('*')\n .contents()\n .filter(isComment)\n .remove();\n\n return $;\n}\n\nexport default function clean($) {\n $(TAGS_TO_REMOVE).remove();\n\n $ = cleanComments($);\n return $;\n}\n","import cheerio from 'cheerio';\n\nimport { fetchResource } from './utils';\nimport {\n normalizeMetaTags,\n convertLazyLoadedImages,\n clean,\n} from './utils/dom';\n\nconst Resource = {\n\n // Create a Resource.\n //\n // :param url: The URL for the document we should retrieve.\n // :param response: If set, use as the response rather than\n // attempting to fetch it ourselves. Expects a\n // string.\n async create(url, preparedResponse, parsedUrl) {\n let result;\n\n if (preparedResponse) {\n const validResponse = {\n statusMessage: 'OK',\n statusCode: 200,\n headers: {\n 'content-type': 'text/html',\n 'content-length': 500,\n },\n };\n\n result = { body: preparedResponse, response: validResponse };\n } else {\n result = await fetchResource(url, parsedUrl);\n }\n\n if (result.error) {\n return result;\n }\n\n return this.generateDoc(result);\n },\n\n generateDoc({ body: content, response }) {\n const { 'content-type': contentType } = response.headers;\n\n // TODO: Implement is_text function from\n // https://github.com/ReadabilityHoldings/readability/blob/8dc89613241d04741ebd42fa9fa7df1b1d746303/readability/utils/text.py#L57\n if (!contentType.includes('html') &&\n !contentType.includes('text')) {\n throw new Error('Content does not appear to be text.');\n }\n\n let $ = cheerio.load(content, { normalizeWhitespace: true });\n\n if ($.root().children().length === 0) {\n throw new Error('No children, likely a bad parse.');\n }\n\n $ = normalizeMetaTags($);\n $ = convertLazyLoadedImages($);\n $ = clean($);\n\n return $;\n },\n};\n\nexport default Resource;\n","export const NYMagExtractor = {\n domain: 'nymag.com',\n content: {\n // Order by most likely. Extractor will stop on first occurrence\n selectors: [\n 'div.article-content',\n 'section.body',\n 'article.article',\n ],\n\n // Selectors to remove from the extracted content\n clean: [\n '.ad',\n '.single-related-story',\n ],\n\n // Object of tranformations to make on matched elements\n // Each key is the selector, each value is the tag to\n // transform to.\n // If a function is given, it should return a string\n // to convert to or nothing (in which case it will not perform\n // the transformation.\n transforms: {\n // Convert h1s to h2s\n h1: 'h2',\n\n // Convert lazy-loaded noscript images to figures\n noscript: ($node) => {\n const $children = $node.children();\n if ($children.length === 1 && $children.get(0).tagName === 'img') {\n return 'figure';\n }\n\n return null;\n },\n },\n },\n\n title: {\n selectors: [\n 'h1.lede-feature-title',\n 'h1.headline-primary',\n 'h1',\n ],\n },\n\n author: {\n selectors: [\n '.by-authors',\n '.lede-feature-author',\n ],\n },\n\n dek: {\n selectors: [\n '.lede-feature-teaser',\n ],\n },\n\n date_published: {\n selectors: [\n ['time.article-timestamp[datetime]', 'datetime'],\n 'time.article-timestamp',\n ],\n },\n};\n","export const BloggerExtractor = {\n domain: 'blogspot.com',\n content: {\n // Blogger is insane and does not load its content\n // initially in the page, but it's all there\n // in noscript\n selectors: [\n '.post-content noscript',\n ],\n\n // Selectors to remove from the extracted content\n clean: [\n ],\n\n // Convert the noscript tag to a div\n transforms: {\n noscript: 'div',\n },\n },\n\n author: {\n selectors: [\n '.post-author-name',\n ],\n },\n\n title: {\n selectors: [\n '.post h2.title',\n ],\n },\n\n date_published: {\n selectors: [\n 'span.publishdate',\n ],\n },\n};\n","export const WikipediaExtractor = {\n domain: 'wikipedia.org',\n content: {\n selectors: [\n '#mw-content-text',\n ],\n\n defaultCleaner: false,\n\n // transform top infobox to an image with caption\n transforms: {\n '.infobox img': ($node) => {\n const $parent = $node.parents('.infobox');\n // Only prepend the first image in .infobox\n if ($parent.children('img').length === 0) {\n $parent.prepend($node);\n }\n },\n '.infobox caption': 'figcaption',\n '.infobox': 'figure',\n },\n\n // Selectors to remove from the extracted content\n clean: [\n '.mw-editsection',\n 'figure tr, figure td, figure tbody',\n '#toc',\n '.navbox',\n ],\n\n },\n\n author: 'Wikipedia Contributors',\n\n title: {\n selectors: [\n 'h2.title',\n ],\n },\n\n date_published: {\n selectors: [\n '#footer-info-lastmod',\n ],\n },\n\n};\n","export const TwitterExtractor = {\n domain: 'twitter.com',\n\n content: {\n transforms: {\n // We're transforming essentially the whole page here.\n // Twitter doesn't have nice selectors, so our initial\n // selector grabs the whole page, then we're re-writing\n // it to fit our needs before we clean it up.\n '.permalink[role=main]': ($node, $) => {\n const tweets = $node.find('.tweet');\n const $tweetContainer = $('
');\n $tweetContainer.append(tweets);\n $node.replaceWith($tweetContainer);\n },\n\n // Twitter wraps @ with s, which\n // renders as a strikethrough\n s: 'span',\n },\n\n selectors: [\n '.permalink[role=main]',\n ],\n\n defaultCleaner: false,\n\n clean: [\n '.stream-item-footer',\n 'button',\n '.tweet-details-fixer',\n ],\n },\n\n author: {\n selectors: [\n '.tweet.permalink-tweet .username',\n ],\n },\n\n date_published: {\n selectors: [\n ['.permalink-tweet ._timestamp[data-time-ms]', 'data-time-ms'],\n // '.tweet.permalink-tweet .metadata',\n ],\n },\n\n};\n","export const NYTimesExtractor = {\n title: {\n selectors: [\n '.g-headline',\n 'h1.headline',\n ],\n },\n\n author: {\n selectors: [\n ['meta[name=\"author\"]', 'value'],\n '.g-byline',\n '.byline',\n ],\n },\n\n content: {\n selectors: [\n 'div.g-blocks',\n 'article#story',\n ],\n\n defaultCleaner: false,\n\n transforms: {\n 'img.g-lazy': ($node) => {\n let src = $node.attr('src');\n // const widths = $node.attr('data-widths')\n // .slice(1)\n // .slice(0, -1)\n // .split(',');\n // if (widths.length) {\n // width = widths.slice(-1);\n // } else {\n // width = '900';\n // }\n const width = 640;\n\n src = src.replace('{{size}}', width);\n $node.attr('src', src);\n },\n },\n\n clean: [\n '.ad',\n 'header#story-header',\n '.story-body-1 .lede.video',\n '.visually-hidden',\n '#newsletter-promo',\n '.promo',\n '.comments-button',\n '.hidden',\n ],\n },\n\n date_published: null,\n\n lead_image_url: null,\n\n dek: null,\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\nexport const TheAtlanticExtractor = {\n domain: 'www.theatlantic.com',\n title: {\n selectors: [\n 'h1.hed',\n ],\n },\n\n author: {\n selectors: [\n 'article#article .article-cover-extra .metadata .byline a',\n ],\n },\n\n content: {\n selectors: [\n '.article-body',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n date_published: null,\n\n lead_image_url: null,\n\n dek: null,\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const NewYorkerExtractor = {\n domain: 'www.newyorker.com',\n title: {\n selectors: [\n 'h1.title',\n ],\n },\n\n author: {\n selectors: [\n '.contributors',\n ],\n },\n\n content: {\n selectors: [\n 'div#articleBody',\n 'div.articleBody',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n date_published: {\n selectors: [\n ['meta[name=\"article:published_time\"]', 'value'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"og:description\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const WiredExtractor = {\n domain: 'www.wired.com',\n title: {\n selectors: [\n 'h1.post-title',\n // enter title selectors\n ],\n },\n\n author: {\n selectors: [\n 'a[rel=\"author\"]',\n // enter author selectors\n ],\n },\n\n content: {\n selectors: [\n 'article.content',\n // enter content selectors\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n '.visually-hidden',\n\n ],\n },\n\n date_published: {\n selectors: [\n ['meta[itemprop=\"datePublished\"]', 'value'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"og:description\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const MSNExtractor = {\n domain: 'www.msn.com',\n title: {\n selectors: [\n 'h1',\n // enter title selectors\n ],\n },\n\n author: {\n selectors: [\n 'span.authorname-txt',\n // enter author selectors\n ],\n },\n\n content: {\n selectors: [\n 'div.richtext',\n // enter content selectors\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n 'span.caption',\n\n ],\n },\n\n date_published: {\n selectors: [\n 'span.time',\n ],\n },\n\n lead_image_url: {\n selectors: [\n\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"description\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const YahooExtractor = {\n domain: 'www.yahoo.com',\n title: {\n selectors: [\n 'header.canvas-header',\n // enter title selectors\n ],\n },\n\n author: {\n selectors: [\n 'span.provider-name',\n // enter author selectors\n ],\n },\n\n content: {\n selectors: [\n // enter content selectors\n '.content-canvas',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n '.figure-caption',\n\n ],\n },\n\n date_published: {\n selectors: [\n ['time.date[datetime]', 'datetime'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"og:description\"]', 'value'],\n // enter dek selectors\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const BuzzfeedExtractor = {\n domain: 'www.buzzfeed.com',\n title: {\n selectors: [\n 'h1[id=\"post-title\"]',\n // enter title selectors\n ],\n },\n\n author: {\n selectors: [\n 'a[data-action=\"user/username\"]', 'byline__author',\n // enter author selectors\n ],\n },\n\n content: {\n selectors: [\n '#buzz_sub_buzz',\n // enter content selectors\n ],\n\n defaultCleaner: false,\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: {\n h2: 'b',\n },\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n '.instapaper_ignore',\n '.suplist_list_hide .buzz_superlist_item .buzz_superlist_number_inline',\n '.share-box',\n ],\n },\n\n date_published: {\n selectors: [\n '.buzz-datetime',\n // enter author selectors\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"description\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const WikiaExtractor = {\n domain: 'fandom.wikia.com',\n title: {\n selectors: [\n 'h1.entry-title',\n // enter title selectors\n ],\n },\n\n author: {\n selectors: [\n '.author vcard', '.fn',\n // enter author selectors\n ],\n },\n\n content: {\n selectors: [\n '.grid-content',\n '.entry-content',\n // enter content selectors\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n date_published: {\n selectors: [\n ['meta[name=\"article:published_time\"]', 'value'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"og:description\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const LittleThingsExtractor = {\n domain: 'www.littlethings.com',\n title: {\n selectors: [\n 'h1.post-title',\n // enter title selectors\n ],\n },\n\n author: {\n selectors: [\n ['meta[name=\"author\"]', 'value'],\n // enter author selectors\n ],\n },\n\n content: {\n selectors: [\n // enter content selectors\n '.mainContentIntro',\n '.content-wrapper',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const PoliticoExtractor = {\n domain: 'www.politico.com',\n title: {\n selectors: [\n // enter title selectors\n ['meta[name=\"og:title\"]', 'value'],\n ],\n },\n\n author: {\n selectors: [\n '.story-main-content .byline .vcard',\n ],\n },\n\n content: {\n selectors: [\n // enter content selectors\n '.story-main-content',\n '.content-group', '.story-core',\n '.story-text',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n 'figcaption',\n ],\n },\n\n date_published: {\n selectors: [\n ['.story-main-content .timestamp time[datetime]', 'datetime'],\n\n ],\n },\n\n lead_image_url: {\n selectors: [\n // enter lead_image_url selectors\n ['meta[name=\"og:image\"]', 'value'],\n\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"description\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","export const DeadspinExtractor = {\n domain: 'deadspin.com',\n title: {\n selectors: [\n 'h1.headline',\n ],\n },\n\n author: {\n selectors: [\n '.author',\n ],\n },\n\n content: {\n selectors: [\n '.post-content',\n '.entry-content',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: {\n 'iframe.lazyload[data-recommend-id^=\"youtube://\"]': ($node) => {\n const youtubeId = $node.attr('id').split('youtube-')[1];\n $node.attr('src', `https://www.youtube.com/embed/${youtubeId}`);\n },\n },\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n ],\n },\n\n date_published: {\n selectors: [\n ['time.updated[datetime]', 'datetime'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n // enter selectors\n ],\n },\n\n next_page_url: {\n selectors: [\n // enter selectors\n ],\n },\n\n excerpt: {\n selectors: [\n // enter selectors\n ],\n },\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const BroadwayWorldExtractor = {\n domain: 'www.broadwayworld.com',\n title: {\n selectors: [\n 'h1.article-title',\n ],\n },\n\n author: {\n selectors: [\n 'span[itemprop=author]',\n ],\n },\n\n content: {\n selectors: [\n 'div[itemprop=articlebody]',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: {\n },\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n date_published: {\n selectors: [\n ['meta[itemprop=datePublished]', 'value'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"og:description\"]', 'value'],\n ],\n },\n\n next_page_url: {\n selectors: [\n // enter selectors\n ],\n },\n\n excerpt: {\n selectors: [\n // enter selectors\n ],\n },\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const ApartmentTherapyExtractor = {\n domain: 'www.apartmenttherapy.com',\n title: {\n selectors: [\n 'h1.headline',\n ],\n },\n\n author: {\n selectors: [\n '.PostByline__name',\n ],\n },\n\n content: {\n selectors: [\n 'div.post__content',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: {\n 'div[data-render-react-id=\"images/LazyPicture\"]': ($node, $) => {\n const data = JSON.parse($node.attr('data-props'));\n const { src } = data.sources[0];\n const $img = $('').attr('src', src);\n $node.replaceWith($img);\n },\n },\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n date_published: {\n selectors: [\n ['.PostByline__timestamp[datetime]', 'datetime'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=description]', 'value'],\n ],\n },\n\n next_page_url: {\n selectors: [\n // enter selectors\n ],\n },\n\n excerpt: {\n selectors: [\n // enter selectors\n ],\n },\n};\n","export const MediumExtractor = {\n domain: 'medium.com',\n title: {\n selectors: [\n 'h1',\n ],\n },\n\n author: {\n selectors: [\n ['meta[name=\"author\"]', 'value'],\n ],\n },\n\n content: {\n selectors: [\n '.section-content',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: {\n // Re-write lazy-loaded youtube videos\n iframe: ($node) => {\n const ytRe =\n /https:\\/\\/i.embed.ly\\/.+url=https:\\/\\/i\\.ytimg\\.com\\/vi\\/(\\w+)\\//;\n const thumb = decodeURIComponent($node.attr('data-thumbnail'));\n\n if (ytRe.test(thumb)) {\n const [_, youtubeId] = thumb.match(ytRe) // eslint-disable-line\n $node.attr('src', `https://www.youtube.com/embed/${youtubeId}`);\n const $parent = $node.parents('figure');\n $parent.prepend($node.clone());\n $node.remove();\n }\n },\n },\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n date_published: {\n selectors: [\n ['time[datetime]', 'datetime'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n // enter selectors\n ],\n },\n\n next_page_url: {\n selectors: [\n // enter selectors\n ],\n },\n\n excerpt: {\n selectors: [\n // enter selectors\n ],\n },\n};\n","import { NYMagExtractor } from './custom/nymag.com';\nimport { BloggerExtractor } from './custom/blogspot.com';\nimport { WikipediaExtractor } from './custom/wikipedia.org';\nimport { TwitterExtractor } from './custom/twitter.com';\nimport { NYTimesExtractor } from './custom/www.nytimes.com';\nimport { TheAtlanticExtractor } from './custom/www.theatlantic.com';\nimport { NewYorkerExtractor } from './custom/www.newyorker.com';\nimport { WiredExtractor } from './custom/www.wired.com';\nimport { MSNExtractor } from './custom/www.msn.com';\nimport { YahooExtractor } from './custom/www.yahoo.com';\nimport { BuzzfeedExtractor } from './custom/www.buzzfeed.com';\nimport { WikiaExtractor } from './custom/fandom.wikia.com';\nimport { LittleThingsExtractor } from './custom/www.littlethings.com';\nimport { PoliticoExtractor } from './custom/www.politico.com';\nimport { DeadspinExtractor } from './custom/deadspin.com';\nimport { BroadwayWorldExtractor } from './custom/www.broadwayworld.com';\nimport { ApartmentTherapyExtractor } from './custom/www.apartmenttherapy.com';\nimport { MediumExtractor } from './custom/medium.com';\n\nconst Extractors = {\n 'nymag.com': NYMagExtractor,\n 'blogspot.com': BloggerExtractor,\n 'wikipedia.org': WikipediaExtractor,\n 'twitter.com': TwitterExtractor,\n 'www.nytimes.com': NYTimesExtractor,\n 'www.theatlantic.com': TheAtlanticExtractor,\n 'www.newyorker.com': NewYorkerExtractor,\n 'www.wired.com': WiredExtractor,\n 'www.msn.com': MSNExtractor,\n 'www.yahoo.com': YahooExtractor,\n 'www.buzzfeed.com': BuzzfeedExtractor,\n 'fandom.wikia.com': WikiaExtractor,\n 'www.littlethings.com': LittleThingsExtractor,\n 'www.politico.com': PoliticoExtractor,\n 'deadspin.com': DeadspinExtractor,\n 'jezebel.com': DeadspinExtractor,\n 'lifehacker.com': DeadspinExtractor,\n 'kotaku.com': DeadspinExtractor,\n 'gizmodo.com': DeadspinExtractor,\n 'jalopnik.com': DeadspinExtractor,\n 'www.broadwayworld.com': BroadwayWorldExtractor,\n 'www.apartmenttherapy.com': ApartmentTherapyExtractor,\n 'medium.com': MediumExtractor,\n};\n\nexport default Extractors;\n","// Spacer images to be removed\nexport const SPACER_RE = new RegExp('trans|transparent|spacer|blank', 'i');\n\n// The class we will use to mark elements we want to keep\n// but would normally remove\nexport const KEEP_CLASS = 'mercury-parser-keep';\n\nexport const KEEP_SELECTORS = [\n 'iframe[src^=\"https://www.youtube.com\"]',\n 'iframe[src^=\"http://www.youtube.com\"]',\n 'iframe[src^=\"https://player.vimeo\"]',\n 'iframe[src^=\"http://player.vimeo\"]',\n];\n\n// A list of tags to strip from the output if we encounter them.\nexport const STRIP_OUTPUT_TAGS = [\n 'title',\n 'script',\n 'noscript',\n 'link',\n 'style',\n 'hr',\n 'embed',\n 'iframe',\n 'object',\n];\n\n// cleanAttributes\nexport const REMOVE_ATTRS = ['style', 'align'];\nexport const REMOVE_ATTR_SELECTORS = REMOVE_ATTRS.map(selector => `[${selector}]`);\nexport const REMOVE_ATTR_LIST = REMOVE_ATTRS.join(',');\nexport const WHITELIST_ATTRS = ['src', 'srcset', 'href', 'class', 'id', 'alt'];\nexport const WHITELIST_ATTRS_RE = new RegExp(`^(${WHITELIST_ATTRS.join('|')})$`, 'i');\n\n// removeEmpty\nexport const REMOVE_EMPTY_TAGS = ['p'];\nexport const REMOVE_EMPTY_SELECTORS = REMOVE_EMPTY_TAGS.map(tag => `${tag}:empty`).join(',');\n\n// cleanTags\nexport const CLEAN_CONDITIONALLY_TAGS = ['ul', 'ol', 'table', 'div', 'button', 'form'].join(',');\n\n// cleanHeaders\nconst HEADER_TAGS = ['h2', 'h3', 'h4', 'h5', 'h6'];\nexport const HEADER_TAG_LIST = HEADER_TAGS.join(',');\n\n\n// // CONTENT FETCHING CONSTANTS ////\n\n// A list of strings that can be considered unlikely candidates when\n// extracting content from a resource. These strings are joined together\n// and then tested for existence using re:test, so may contain simple,\n// non-pipe style regular expression queries if necessary.\nexport const UNLIKELY_CANDIDATES_BLACKLIST = [\n 'ad-break',\n 'adbox',\n 'advert',\n 'addthis',\n 'agegate',\n 'aux',\n 'blogger-labels',\n 'combx',\n 'comment',\n 'conversation',\n 'disqus',\n 'entry-unrelated',\n 'extra',\n 'foot',\n // 'form', // This is too generic, has too many false positives\n 'header',\n 'hidden',\n 'loader',\n 'login', // Note: This can hit 'blogindex'.\n 'menu',\n 'meta',\n 'nav',\n 'outbrain',\n 'pager',\n 'pagination',\n 'predicta', // readwriteweb inline ad box\n 'presence_control_external', // lifehacker.com container full of false positives\n 'popup',\n 'printfriendly',\n 'related',\n 'remove',\n 'remark',\n 'rss',\n 'share',\n 'shoutbox',\n 'sidebar',\n 'sociable',\n 'sponsor',\n 'taboola',\n 'tools',\n];\n\n// A list of strings that can be considered LIKELY candidates when\n// extracting content from a resource. Essentially, the inverse of the\n// blacklist above - if something matches both blacklist and whitelist,\n// it is kept. This is useful, for example, if something has a className\n// of \"rss-content entry-content\". It matched 'rss', so it would normally\n// be removed, however, it's also the entry content, so it should be left\n// alone.\n//\n// These strings are joined together and then tested for existence using\n// re:test, so may contain simple, non-pipe style regular expression queries\n// if necessary.\nexport const UNLIKELY_CANDIDATES_WHITELIST = [\n 'and',\n 'article',\n 'body',\n 'blogindex',\n 'column',\n 'content',\n 'entry-content-asset',\n 'format', // misuse of form\n 'hfeed',\n 'hentry',\n 'hatom',\n 'main',\n 'page',\n 'posts',\n 'shadow',\n];\n\n// A list of tags which, if found inside, should cause a
to NOT\n// be turned into a paragraph tag. Shallow div tags without these elements\n// should be turned into

tags.\nexport const DIV_TO_P_BLOCK_TAGS = [\n 'a',\n 'blockquote',\n 'dl',\n 'div',\n 'img',\n 'p',\n 'pre',\n 'table',\n].join(',');\n\n// A list of tags that should be ignored when trying to find the top candidate\n// for a document.\nexport const NON_TOP_CANDIDATE_TAGS = [\n 'br',\n 'b',\n 'i',\n 'label',\n 'hr',\n 'area',\n 'base',\n 'basefont',\n 'input',\n 'img',\n 'link',\n 'meta',\n];\n\nexport const NON_TOP_CANDIDATE_TAGS_RE =\n new RegExp(`^(${NON_TOP_CANDIDATE_TAGS.join('|')})$`, 'i');\n\n// A list of selectors that specify, very clearly, either hNews or other\n// very content-specific style content, like Blogger templates.\n// More examples here: http://microformats.org/wiki/blog-post-formats\nexport const HNEWS_CONTENT_SELECTORS = [\n ['.hentry', '.entry-content'],\n ['entry', '.entry-content'],\n ['.entry', '.entry_content'],\n ['.post', '.postbody'],\n ['.post', '.post_body'],\n ['.post', '.post-body'],\n];\n\nexport const PHOTO_HINTS = [\n 'figure',\n 'photo',\n 'image',\n 'caption',\n];\nexport const PHOTO_HINTS_RE = new RegExp(PHOTO_HINTS.join('|'), 'i');\n\n\n// A list of strings that denote a positive scoring for this content as being\n// an article container. Checked against className and id.\n//\n// TODO: Perhaps have these scale based on their odds of being quality?\nexport const POSITIVE_SCORE_HINTS = [\n 'article',\n 'articlecontent',\n 'instapaper_body',\n 'blog',\n 'body',\n 'content',\n 'entry-content-asset',\n 'entry',\n 'hentry',\n 'main',\n 'Normal',\n 'page',\n 'pagination',\n 'permalink',\n 'post',\n 'story',\n 'text',\n '[-_]copy', // usatoday\n '\\\\Bcopy',\n];\n\n// The above list, joined into a matching regular expression\nexport const POSITIVE_SCORE_RE = new RegExp(POSITIVE_SCORE_HINTS.join('|'), 'i');\n\n// Readability publisher-specific guidelines\nexport const READABILITY_ASSET = new RegExp('entry-content-asset', 'i');\n\n// A list of strings that denote a negative scoring for this content as being\n// an article container. Checked against className and id.\n//\n// TODO: Perhaps have these scale based on their odds of being quality?\nexport const NEGATIVE_SCORE_HINTS = [\n 'adbox',\n 'advert',\n 'author',\n 'bio',\n 'bookmark',\n 'bottom',\n 'byline',\n 'clear',\n 'com-',\n 'combx',\n 'comment',\n 'comment\\\\B',\n 'contact',\n 'copy',\n 'credit',\n 'crumb',\n 'date',\n 'deck',\n 'excerpt',\n 'featured', // tnr.com has a featured_content which throws us off\n 'foot',\n 'footer',\n 'footnote',\n 'graf',\n 'head',\n 'info',\n 'infotext', // newscientist.com copyright\n 'instapaper_ignore',\n 'jump',\n 'linebreak',\n 'link',\n 'masthead',\n 'media',\n 'meta',\n 'modal',\n 'outbrain', // slate.com junk\n 'promo',\n 'pr_', // autoblog - press release\n 'related',\n 'respond',\n 'roundcontent', // lifehacker restricted content warning\n 'scroll',\n 'secondary',\n 'share',\n 'shopping',\n 'shoutbox',\n 'side',\n 'sidebar',\n 'sponsor',\n 'stamp',\n 'sub',\n 'summary',\n 'tags',\n 'tools',\n 'widget',\n];\n// The above list, joined into a matching regular expression\nexport const NEGATIVE_SCORE_RE = new RegExp(NEGATIVE_SCORE_HINTS.join('|'), 'i');\n\n// XPath to try to determine if a page is wordpress. Not always successful.\nexport const IS_WP_SELECTOR = 'meta[name=generator][value^=WordPress]';\n\n// Match a digit. Pretty clear.\nexport const DIGIT_RE = new RegExp('[0-9]');\n\n// A list of words that, if found in link text or URLs, likely mean that\n// this link is not a next page link.\nexport const EXTRANEOUS_LINK_HINTS = [\n 'print',\n 'archive',\n 'comment',\n 'discuss',\n 'e-mail',\n 'email',\n 'share',\n 'reply',\n 'all',\n 'login',\n 'sign',\n 'single',\n 'adx',\n 'entry-unrelated',\n];\nexport const EXTRANEOUS_LINK_HINTS_RE = new RegExp(EXTRANEOUS_LINK_HINTS.join('|'), 'i');\n\n// Match any phrase that looks like it could be page, or paging, or pagination\nexport const PAGE_RE = new RegExp('pag(e|ing|inat)', 'i');\n\n// Match any link text/classname/id that looks like it could mean the next\n// page. Things like: next, continue, >, >>, » but not >|, »| as those can\n// mean last page.\n// export const NEXT_LINK_TEXT_RE = new RegExp('(next|weiter|continue|>([^\\|]|$)|»([^\\|]|$))', 'i');\nexport const NEXT_LINK_TEXT_RE = /(next|weiter|continue|>([^\\|]|$)|»([^\\|]|$))/i;\n\n// Match any link text/classname/id that looks like it is an end link: things\n// like \"first\", \"last\", \"end\", etc.\nexport const CAP_LINK_TEXT_RE = new RegExp('(first|last|end)', 'i');\n\n// Match any link text/classname/id that looks like it means the previous\n// page.\nexport const PREV_LINK_TEXT_RE = new RegExp('(prev|earl|old|new|<|«)', 'i');\n\n// Match 2 or more consecutive
tags\nexport const BR_TAGS_RE = new RegExp('(]*>[ \\n\\r\\t]*){2,}', 'i');\n\n// Match 1 BR tag.\nexport const BR_TAG_RE = new RegExp(']*>', 'i');\n\n// A list of all of the block level tags known in HTML5 and below. Taken from\n// http://bit.ly/qneNIT\nexport const BLOCK_LEVEL_TAGS = [\n 'article',\n 'aside',\n 'blockquote',\n 'body',\n 'br',\n 'button',\n 'canvas',\n 'caption',\n 'col',\n 'colgroup',\n 'dd',\n 'div',\n 'dl',\n 'dt',\n 'embed',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hgroup',\n 'hr',\n 'li',\n 'map',\n 'object',\n 'ol',\n 'output',\n 'p',\n 'pre',\n 'progress',\n 'section',\n 'table',\n 'tbody',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'tr',\n 'ul',\n 'video',\n];\nexport const BLOCK_LEVEL_TAGS_RE = new RegExp(`^(${BLOCK_LEVEL_TAGS.join('|')})$`, 'i');\n\n\n// The removal is implemented as a blacklist and whitelist, this test finds\n// blacklisted elements that aren't whitelisted. We do this all in one\n// expression-both because it's only one pass, and because this skips the\n// serialization for whitelisted nodes.\nconst candidatesBlacklist = UNLIKELY_CANDIDATES_BLACKLIST.join('|');\nexport const CANDIDATES_BLACKLIST = new RegExp(candidatesBlacklist, 'i');\n\nconst candidatesWhitelist = UNLIKELY_CANDIDATES_WHITELIST.join('|');\nexport const CANDIDATES_WHITELIST = new RegExp(candidatesWhitelist, 'i');\n\nexport const UNLIKELY_RE = new RegExp(`!(${candidatesWhitelist})|(${candidatesBlacklist})`, 'i');\n\n\nexport const PARAGRAPH_SCORE_TAGS = new RegExp('^(p|li|span|pre)$', 'i');\nexport const CHILD_CONTENT_TAGS = new RegExp('^(td|blockquote|ol|ul|dl)$', 'i');\nexport const BAD_TAGS = new RegExp('^(address|form)$', 'i');\n\nexport const HTML_OR_BODY_RE = new RegExp('^(html|body)$', 'i');\n","import {\n CANDIDATES_WHITELIST,\n CANDIDATES_BLACKLIST,\n} from './constants';\n\nexport default function stripUnlikelyCandidates($) {\n // Loop through the provided document and remove any non-link nodes\n // that are unlikely candidates for article content.\n //\n // Links are ignored because there are very often links to content\n // that are identified as non-body-content, but may be inside\n // article-like content.\n //\n // :param $: a cheerio object to strip nodes from\n // :return $: the cleaned cheerio object\n $('*').not('a').each((index, node) => {\n const $node = $(node);\n const classes = $node.attr('class');\n const id = $node.attr('id');\n if (!id && !classes) return;\n\n const classAndId = `${classes || ''} ${id || ''}`;\n if (CANDIDATES_WHITELIST.test(classAndId)) {\n return;\n } else if (CANDIDATES_BLACKLIST.test(classAndId)) {\n $node.remove();\n }\n });\n\n return $;\n}\n","import { paragraphize } from './index';\n\n// ## NOTES:\n// Another good candidate for refactoring/optimizing.\n// Very imperative code, I don't love it. - AP\n\n\n// Given cheerio object, convert consecutive
tags into\n//

tags instead.\n//\n// :param $: A cheerio object\n\nexport default function brsToPs($) {\n let collapsing = false;\n $('br').each((index, element) => {\n const nextElement = $(element).next().get(0);\n\n if (nextElement && nextElement.tagName === 'br') {\n collapsing = true;\n $(element).remove();\n } else if (collapsing) {\n collapsing = false;\n // $(element).replaceWith('

')\n paragraphize(element, $, true);\n }\n });\n\n return $;\n}\n","import { BLOCK_LEVEL_TAGS_RE } from './constants';\n\n// Given a node, turn it into a P if it is not already a P, and\n// make sure it conforms to the constraints of a P tag (I.E. does\n// not contain any other block tags.)\n//\n// If the node is a
, it treats the following inline siblings\n// as if they were its children.\n//\n// :param node: The node to paragraphize; this is a raw node\n// :param $: The cheerio object to handle dom manipulation\n// :param br: Whether or not the passed node is a br\n\nexport default function paragraphize(node, $, br = false) {\n const $node = $(node);\n\n if (br) {\n let sibling = node.nextSibling;\n const p = $('

');\n\n // while the next node is text or not a block level element\n // append it to a new p node\n while (sibling && !(sibling.tagName && BLOCK_LEVEL_TAGS_RE.test(sibling.tagName))) {\n const nextSibling = sibling.nextSibling;\n $(sibling).appendTo(p);\n sibling = nextSibling;\n }\n\n $node.replaceWith(p);\n $node.remove();\n return $;\n }\n\n return $;\n}\n","import { brsToPs, convertNodeTo } from 'utils/dom';\n\nimport { DIV_TO_P_BLOCK_TAGS } from './constants';\n\nfunction convertDivs($) {\n $('div').each((index, div) => {\n const $div = $(div);\n const convertable = $div.children(DIV_TO_P_BLOCK_TAGS).length === 0;\n\n if (convertable) {\n convertNodeTo($div, $, 'p');\n }\n });\n\n return $;\n}\n\nfunction convertSpans($) {\n $('span').each((index, span) => {\n const $span = $(span);\n const convertable = $span.parents('p, div').length === 0;\n if (convertable) {\n convertNodeTo($span, $, 'p');\n }\n });\n\n return $;\n}\n\n// Loop through the provided doc, and convert any p-like elements to\n// actual paragraph tags.\n//\n// Things fitting this criteria:\n// * Multiple consecutive
tags.\n// *
tags without block level elements inside of them\n// * tags who are not children of

or

tags.\n//\n// :param $: A cheerio object to search\n// :return cheerio object with new p elements\n// (By-reference mutation, though. Returned just for convenience.)\n\nexport default function convertToParagraphs($) {\n $ = brsToPs($);\n $ = convertDivs($);\n $ = convertSpans($);\n\n return $;\n}\n","export default function convertNodeTo($node, $, tag = 'p') {\n const node = $node.get(0);\n if (!node) {\n return $;\n }\n const { attribs } = $node.get(0);\n const attribString = Reflect.ownKeys(attribs)\n .map(key => `${key}=${attribs[key]}`)\n .join(' ');\n\n $node.replaceWith(`<${tag} ${attribString}>${$node.contents()}`);\n return $;\n}\n","import { SPACER_RE } from './constants';\n\nfunction cleanForHeight($img, $) {\n const height = parseInt($img.attr('height'), 10);\n const width = parseInt($img.attr('width'), 10) || 20;\n\n // Remove images that explicitly have very small heights or\n // widths, because they are most likely shims or icons,\n // which aren't very useful for reading.\n if ((height || 20) < 10 || width < 10) {\n $img.remove();\n } else if (height) {\n // Don't ever specify a height on images, so that we can\n // scale with respect to width without screwing up the\n // aspect ratio.\n $img.removeAttr('height');\n }\n\n return $;\n}\n\n// Cleans out images where the source string matches transparent/spacer/etc\n// TODO This seems very aggressive - AP\nfunction removeSpacers($img, $) {\n if (SPACER_RE.test($img.attr('src'))) {\n $img.remove();\n }\n\n return $;\n}\n\nexport default function cleanImages($article, $) {\n $article.find('img').each((index, img) => {\n const $img = $(img);\n\n cleanForHeight($img, $);\n removeSpacers($img, $);\n });\n\n return $;\n}\n","import URL from 'url';\n\nimport {\n KEEP_SELECTORS,\n KEEP_CLASS,\n} from './constants';\n\nexport default function markToKeep(article, $, url, tags = []) {\n if (tags.length === 0) {\n tags = KEEP_SELECTORS;\n }\n\n if (url) {\n const { protocol, hostname } = URL.parse(url);\n tags = [...tags, `iframe[src^=\"${protocol}//${hostname}\"]`];\n }\n\n $(tags.join(','), article).addClass(KEEP_CLASS);\n\n return $;\n}\n","import {\n STRIP_OUTPUT_TAGS,\n KEEP_CLASS,\n} from './constants';\n\nexport default function stripJunkTags(article, $, tags = []) {\n if (tags.length === 0) {\n tags = STRIP_OUTPUT_TAGS;\n }\n\n // Remove matching elements, but ignore\n // any element with a class of mercury-parser-keep\n $(tags.join(','), article).not(`.${KEEP_CLASS}`).remove();\n\n // Remove the mercury-parser-keep class from result\n $(`.${KEEP_CLASS}`, article).removeClass(KEEP_CLASS);\n\n return $;\n}\n","import { convertNodeTo } from 'utils/dom';\n\n// H1 tags are typically the article title, which should be extracted\n// by the title extractor instead. If there's less than 3 of them (<3),\n// strip them. Otherwise, turn 'em into H2s.\nexport default function cleanHOnes(article, $) {\n const $hOnes = $('h1', article);\n\n if ($hOnes.length < 3) {\n $hOnes.each((index, node) => $(node).remove());\n } else {\n $hOnes.each((index, node) => {\n convertNodeTo($(node), $, 'h2');\n });\n }\n\n return $;\n}\n","import { WHITELIST_ATTRS_RE } from './constants';\n\nfunction removeAllButWhitelist($article) {\n $article.find('*').each((index, node) => {\n node.attribs = Reflect.ownKeys(node.attribs).reduce((acc, attr) => {\n if (WHITELIST_ATTRS_RE.test(attr)) {\n return { ...acc, [attr]: node.attribs[attr] };\n }\n\n return acc;\n }, {});\n });\n\n return $article;\n}\n\n// function removeAttrs(article, $) {\n// REMOVE_ATTRS.forEach((attr) => {\n// $(`[${attr}]`, article).removeAttr(attr);\n// });\n// }\n\n// Remove attributes like style or align\nexport default function cleanAttributes($article) {\n // Grabbing the parent because at this point\n // $article will be wrapped in a div which will\n // have a score set on it.\n return removeAllButWhitelist(\n $article.parent().length ?\n $article.parent() : $article\n );\n}\n","export default function removeEmpty($article, $) {\n $article.find('p').each((index, p) => {\n const $p = $(p);\n if ($p.find('iframe, img').length === 0 && $p.text().trim() === '') $p.remove();\n });\n\n return $;\n}\n","// // CONTENT FETCHING CONSTANTS ////\n\n// A list of strings that can be considered unlikely candidates when\n// extracting content from a resource. These strings are joined together\n// and then tested for existence using re:test, so may contain simple,\n// non-pipe style regular expression queries if necessary.\nexport const UNLIKELY_CANDIDATES_BLACKLIST = [\n 'ad-break',\n 'adbox',\n 'advert',\n 'addthis',\n 'agegate',\n 'aux',\n 'blogger-labels',\n 'combx',\n 'comment',\n 'conversation',\n 'disqus',\n 'entry-unrelated',\n 'extra',\n 'foot',\n 'form',\n 'header',\n 'hidden',\n 'loader',\n 'login', // Note: This can hit 'blogindex'.\n 'menu',\n 'meta',\n 'nav',\n 'pager',\n 'pagination',\n 'predicta', // readwriteweb inline ad box\n 'presence_control_external', // lifehacker.com container full of false positives\n 'popup',\n 'printfriendly',\n 'related',\n 'remove',\n 'remark',\n 'rss',\n 'share',\n 'shoutbox',\n 'sidebar',\n 'sociable',\n 'sponsor',\n 'tools',\n];\n\n// A list of strings that can be considered LIKELY candidates when\n// extracting content from a resource. Essentially, the inverse of the\n// blacklist above - if something matches both blacklist and whitelist,\n// it is kept. This is useful, for example, if something has a className\n// of \"rss-content entry-content\". It matched 'rss', so it would normally\n// be removed, however, it's also the entry content, so it should be left\n// alone.\n//\n// These strings are joined together and then tested for existence using\n// re:test, so may contain simple, non-pipe style regular expression queries\n// if necessary.\nexport const UNLIKELY_CANDIDATES_WHITELIST = [\n 'and',\n 'article',\n 'body',\n 'blogindex',\n 'column',\n 'content',\n 'entry-content-asset',\n 'format', // misuse of form\n 'hfeed',\n 'hentry',\n 'hatom',\n 'main',\n 'page',\n 'posts',\n 'shadow',\n];\n\n// A list of tags which, if found inside, should cause a
to NOT\n// be turned into a paragraph tag. Shallow div tags without these elements\n// should be turned into

tags.\nexport const DIV_TO_P_BLOCK_TAGS = [\n 'a',\n 'blockquote',\n 'dl',\n 'div',\n 'img',\n 'p',\n 'pre',\n 'table',\n].join(',');\n\n// A list of tags that should be ignored when trying to find the top candidate\n// for a document.\nexport const NON_TOP_CANDIDATE_TAGS = [\n 'br',\n 'b',\n 'i',\n 'label',\n 'hr',\n 'area',\n 'base',\n 'basefont',\n 'input',\n 'img',\n 'link',\n 'meta',\n];\n\nexport const NON_TOP_CANDIDATE_TAGS_RE =\n new RegExp(`^(${NON_TOP_CANDIDATE_TAGS.join('|')})$`, 'i');\n\n// A list of selectors that specify, very clearly, either hNews or other\n// very content-specific style content, like Blogger templates.\n// More examples here: http://microformats.org/wiki/blog-post-formats\nexport const HNEWS_CONTENT_SELECTORS = [\n ['.hentry', '.entry-content'],\n ['entry', '.entry-content'],\n ['.entry', '.entry_content'],\n ['.post', '.postbody'],\n ['.post', '.post_body'],\n ['.post', '.post-body'],\n];\n\nexport const PHOTO_HINTS = [\n 'figure',\n 'photo',\n 'image',\n 'caption',\n];\nexport const PHOTO_HINTS_RE = new RegExp(PHOTO_HINTS.join('|'), 'i');\n\n\n// A list of strings that denote a positive scoring for this content as being\n// an article container. Checked against className and id.\n//\n// TODO: Perhaps have these scale based on their odds of being quality?\nexport const POSITIVE_SCORE_HINTS = [\n 'article',\n 'articlecontent',\n 'instapaper_body',\n 'blog',\n 'body',\n 'content',\n 'entry-content-asset',\n 'entry',\n 'hentry',\n 'main',\n 'Normal',\n 'page',\n 'pagination',\n 'permalink',\n 'post',\n 'story',\n 'text',\n '[-_]copy', // usatoday\n '\\\\Bcopy',\n];\n\n// The above list, joined into a matching regular expression\nexport const POSITIVE_SCORE_RE = new RegExp(POSITIVE_SCORE_HINTS.join('|'), 'i');\n\n// Readability publisher-specific guidelines\nexport const READABILITY_ASSET = new RegExp('entry-content-asset', 'i');\n\n// A list of strings that denote a negative scoring for this content as being\n// an article container. Checked against className and id.\n//\n// TODO: Perhaps have these scale based on their odds of being quality?\nexport const NEGATIVE_SCORE_HINTS = [\n 'adbox',\n 'advert',\n 'author',\n 'bio',\n 'bookmark',\n 'bottom',\n 'byline',\n 'clear',\n 'com-',\n 'combx',\n 'comment',\n 'comment\\\\B',\n 'contact',\n 'copy',\n 'credit',\n 'crumb',\n 'date',\n 'deck',\n 'excerpt',\n 'featured', // tnr.com has a featured_content which throws us off\n 'foot',\n 'footer',\n 'footnote',\n 'graf',\n 'head',\n 'info',\n 'infotext', // newscientist.com copyright\n 'instapaper_ignore',\n 'jump',\n 'linebreak',\n 'link',\n 'masthead',\n 'media',\n 'meta',\n 'modal',\n 'outbrain', // slate.com junk\n 'promo',\n 'pr_', // autoblog - press release\n 'related',\n 'respond',\n 'roundcontent', // lifehacker restricted content warning\n 'scroll',\n 'secondary',\n 'share',\n 'shopping',\n 'shoutbox',\n 'side',\n 'sidebar',\n 'sponsor',\n 'stamp',\n 'sub',\n 'summary',\n 'tags',\n 'tools',\n 'widget',\n];\n// The above list, joined into a matching regular expression\nexport const NEGATIVE_SCORE_RE = new RegExp(NEGATIVE_SCORE_HINTS.join('|'), 'i');\n\n// Match a digit. Pretty clear.\nexport const DIGIT_RE = new RegExp('[0-9]');\n\n// Match 2 or more consecutive
tags\nexport const BR_TAGS_RE = new RegExp('(]*>[ \\n\\r\\t]*){2,}', 'i');\n\n// Match 1 BR tag.\nexport const BR_TAG_RE = new RegExp(']*>', 'i');\n\n// A list of all of the block level tags known in HTML5 and below. Taken from\n// http://bit.ly/qneNIT\nexport const BLOCK_LEVEL_TAGS = [\n 'article',\n 'aside',\n 'blockquote',\n 'body',\n 'br',\n 'button',\n 'canvas',\n 'caption',\n 'col',\n 'colgroup',\n 'dd',\n 'div',\n 'dl',\n 'dt',\n 'embed',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hgroup',\n 'hr',\n 'li',\n 'map',\n 'object',\n 'ol',\n 'output',\n 'p',\n 'pre',\n 'progress',\n 'section',\n 'table',\n 'tbody',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'tr',\n 'ul',\n 'video',\n];\nexport const BLOCK_LEVEL_TAGS_RE = new RegExp(`^(${BLOCK_LEVEL_TAGS.join('|')})$`, 'i');\n\n\n// The removal is implemented as a blacklist and whitelist, this test finds\n// blacklisted elements that aren't whitelisted. We do this all in one\n// expression-both because it's only one pass, and because this skips the\n// serialization for whitelisted nodes.\nconst candidatesBlacklist = UNLIKELY_CANDIDATES_BLACKLIST.join('|');\nexport const CANDIDATES_BLACKLIST = new RegExp(candidatesBlacklist, 'i');\n\nconst candidatesWhitelist = UNLIKELY_CANDIDATES_WHITELIST.join('|');\nexport const CANDIDATES_WHITELIST = new RegExp(candidatesWhitelist, 'i');\n\nexport const UNLIKELY_RE = new RegExp(`!(${candidatesWhitelist})|(${candidatesBlacklist})`, 'i');\n\n\nexport const PARAGRAPH_SCORE_TAGS = new RegExp('^(p|li|span|pre)$', 'i');\nexport const CHILD_CONTENT_TAGS = new RegExp('^(td|blockquote|ol|ul|dl)$', 'i');\nexport const BAD_TAGS = new RegExp('^(address|form)$', 'i');\n\nexport const HTML_OR_BODY_RE = new RegExp('^(html|body)$', 'i');\n","import {\n NEGATIVE_SCORE_RE,\n POSITIVE_SCORE_RE,\n PHOTO_HINTS_RE,\n READABILITY_ASSET,\n} from './constants';\n\n\n// Get the score of a node based on its className and id.\nexport default function getWeight(node) {\n const classes = node.attr('class');\n const id = node.attr('id');\n let score = 0;\n\n if (id) {\n // if id exists, try to score on both positive and negative\n if (POSITIVE_SCORE_RE.test(id)) {\n score += 25;\n }\n if (NEGATIVE_SCORE_RE.test(id)) {\n score -= 25;\n }\n }\n\n if (classes) {\n if (score === 0) {\n // if classes exist and id did not contribute to score\n // try to score on both positive and negative\n if (POSITIVE_SCORE_RE.test(classes)) {\n score += 25;\n }\n if (NEGATIVE_SCORE_RE.test(classes)) {\n score -= 25;\n }\n }\n\n // even if score has been set by id, add score for\n // possible photo matches\n // \"try to keep photos if we can\"\n if (PHOTO_HINTS_RE.test(classes)) {\n score += 10;\n }\n\n // add 25 if class matches entry-content-asset,\n // a class apparently instructed for use in the\n // Readability publisher guidelines\n // https://www.readability.com/developers/guidelines\n if (READABILITY_ASSET.test(classes)) {\n score += 25;\n }\n }\n\n return score;\n}\n\n","// returns the score of a node based on\n// the node's score attribute\n// returns null if no score set\nexport default function getScore($node) {\n return parseFloat($node.attr('score')) || null;\n}\n","// return 1 for every comma in text\nexport default function scoreCommas(text) {\n return (text.match(/,/g) || []).length;\n}\n\n","const idkRe = new RegExp('^(p|pre)$', 'i');\n\nexport default function scoreLength(textLength, tagName = 'p') {\n const chunks = textLength / 50;\n\n if (chunks > 0) {\n let lengthBonus;\n\n // No idea why p or pre are being tamped down here\n // but just following the source for now\n // Not even sure why tagName is included here,\n // since this is only being called from the context\n // of scoreParagraph\n if (idkRe.test(tagName)) {\n lengthBonus = chunks - 2;\n } else {\n lengthBonus = chunks - 1.25;\n }\n\n return Math.min(Math.max(lengthBonus, 0), 3);\n }\n\n return 0;\n}\n\n","import {\n scoreCommas,\n scoreLength,\n} from './index';\n\n// Score a paragraph using various methods. Things like number of\n// commas, etc. Higher is better.\nexport default function scoreParagraph(node) {\n let score = 1;\n const text = node.text().trim();\n const textLength = text.length;\n\n // If this paragraph is less than 25 characters, don't count it.\n if (textLength < 25) {\n return 0;\n }\n\n // Add points for any commas within this paragraph\n score += scoreCommas(text);\n\n // For every 50 characters in this paragraph, add another point. Up\n // to 3 points.\n score += scoreLength(textLength);\n\n // Articles can end with short paragraphs when people are being clever\n // but they can also end with short paragraphs setting up lists of junk\n // that we strip. This negative tweaks junk setup paragraphs just below\n // the cutoff threshold.\n if (text.slice(-1) === ':') {\n score -= 1;\n }\n\n return score;\n}\n\n","\nexport default function setScore($node, $, score) {\n $node.attr('score', score);\n return $node;\n}\n\n","import {\n getOrInitScore,\n setScore,\n} from './index';\n\nexport default function addScore($node, $, amount) {\n try {\n const score = getOrInitScore($node, $) + amount;\n setScore($node, $, score);\n } catch (e) {\n // Ignoring; error occurs in scoreNode\n }\n\n return $node;\n}\n","import { addScore } from './index';\n\n// Adds 1/4 of a child's score to its parent\nexport default function addToParent(node, $, score) {\n const parent = node.parent();\n if (parent) {\n addScore(parent, $, score * 0.25);\n }\n\n return node;\n}\n","import {\n getScore,\n scoreNode,\n getWeight,\n addToParent,\n} from './index';\n\n// gets and returns the score if it exists\n// if not, initializes a score based on\n// the node's tag type\nexport default function getOrInitScore($node, $, weightNodes = true) {\n let score = getScore($node);\n\n if (score) {\n return score;\n }\n\n score = scoreNode($node);\n\n if (weightNodes) {\n score += getWeight($node);\n }\n\n addToParent($node, $, score);\n\n return score;\n}\n\n","import { scoreParagraph } from './index';\nimport {\n PARAGRAPH_SCORE_TAGS,\n CHILD_CONTENT_TAGS,\n BAD_TAGS,\n} from './constants';\n\n// Score an individual node. Has some smarts for paragraphs, otherwise\n// just scores based on tag.\nexport default function scoreNode($node) {\n const { tagName } = $node.get(0);\n\n // TODO: Consider ordering by most likely.\n // E.g., if divs are a more common tag on a page,\n // Could save doing that regex test on every node – AP\n if (PARAGRAPH_SCORE_TAGS.test(tagName)) {\n return scoreParagraph($node);\n } else if (tagName === 'div') {\n return 5;\n } else if (CHILD_CONTENT_TAGS.test(tagName)) {\n return 3;\n } else if (BAD_TAGS.test(tagName)) {\n return -3;\n } else if (tagName === 'th') {\n return -5;\n }\n\n return 0;\n}\n","import { convertNodeTo } from 'utils/dom';\n\nimport { HNEWS_CONTENT_SELECTORS } from './constants';\nimport {\n scoreNode,\n setScore,\n getOrInitScore,\n addScore,\n} from './index';\n\nfunction convertSpans($node, $) {\n if ($node.get(0)) {\n const { tagName } = $node.get(0);\n\n if (tagName === 'span') {\n // convert spans to divs\n convertNodeTo($node, $, 'div');\n }\n }\n}\n\nfunction addScoreTo($node, $, score) {\n if ($node) {\n convertSpans($node, $);\n addScore($node, $, score);\n }\n}\n\nfunction scorePs($, weightNodes) {\n $('p, pre').not('[score]').each((index, node) => {\n // The raw score for this paragraph, before we add any parent/child\n // scores.\n let $node = $(node);\n $node = setScore($node, $, getOrInitScore($node, $, weightNodes));\n\n const $parent = $node.parent();\n const rawScore = scoreNode($node);\n\n addScoreTo($parent, $, rawScore, weightNodes);\n if ($parent) {\n // Add half of the individual content score to the\n // grandparent\n addScoreTo($parent.parent(), $, rawScore / 2, weightNodes);\n }\n });\n\n return $;\n}\n\n// score content. Parents get the full value of their children's\n// content score, grandparents half\nexport default function scoreContent($, weightNodes = true) {\n // First, look for special hNews based selectors and give them a big\n // boost, if they exist\n HNEWS_CONTENT_SELECTORS.forEach(([parentSelector, childSelector]) => {\n $(`${parentSelector} ${childSelector}`).each((index, node) => {\n addScore($(node).parent(parentSelector), $, 80);\n });\n });\n\n // Doubling this again\n // Previous solution caused a bug\n // in which parents weren't retaining\n // scores. This is not ideal, and\n // should be fixed.\n scorePs($, weightNodes);\n scorePs($, weightNodes);\n\n return $;\n}\n","const NORMALIZE_RE = /\\s{2,}/g;\n\nexport default function normalizeSpaces(text) {\n return text.replace(NORMALIZE_RE, ' ').trim();\n}\n","// Given a node type to search for, and a list of regular expressions,\n// look to see if this extraction can be found in the URL. Expects\n// that each expression in r_list will return group(1) as the proper\n// string to be cleaned.\n// Only used for date_published currently.\nexport default function extractFromUrl(url, regexList) {\n const matchRe = regexList.find(re => re.test(url));\n if (matchRe) {\n return matchRe.exec(url)[1];\n }\n\n return null;\n}\n","// An expression that looks to try to find the page digit within a URL, if\n// it exists.\n// Matches:\n// page=1\n// pg=1\n// p=1\n// paging=12\n// pag=7\n// pagination/1\n// paging/88\n// pa/83\n// p/11\n//\n// Does not match:\n// pg=102\n// page:2\nexport const PAGE_IN_HREF_RE = new RegExp('(page|paging|(p(a|g|ag)?(e|enum|ewanted|ing|ination)))?(=|/)([0-9]{1,3})', 'i');\n\nexport const HAS_ALPHA_RE = /[a-z]/i;\n\nexport const IS_ALPHA_RE = /^[a-z]+$/i;\nexport const IS_DIGIT_RE = /^[0-9]+$/i;\n","import { PAGE_IN_HREF_RE } from './constants';\n\nexport default function pageNumFromUrl(url) {\n const matches = url.match(PAGE_IN_HREF_RE);\n if (!matches) return null;\n\n const pageNum = parseInt(matches[6], 10);\n\n // Return pageNum < 100, otherwise\n // return null\n return pageNum < 100 ? pageNum : null;\n}\n","export default function removeAnchor(url) {\n return url.split('#')[0].replace(/\\/$/, '');\n}\n","import URL from 'url';\nimport {\n HAS_ALPHA_RE,\n IS_ALPHA_RE,\n IS_DIGIT_RE,\n PAGE_IN_HREF_RE,\n} from './constants';\n\nfunction isGoodSegment(segment, index, firstSegmentHasLetters) {\n let goodSegment = true;\n\n // If this is purely a number, and it's the first or second\n // url_segment, it's probably a page number. Remove it.\n if (index < 2 && IS_DIGIT_RE.test(segment) && segment.length < 3) {\n goodSegment = true;\n }\n\n // If this is the first url_segment and it's just \"index\",\n // remove it\n if (index === 0 && segment.toLowerCase() === 'index') {\n goodSegment = false;\n }\n\n // If our first or second url_segment is smaller than 3 characters,\n // and the first url_segment had no alphas, remove it.\n if (index < 2 && segment.length < 3 && !firstSegmentHasLetters) {\n goodSegment = false;\n }\n\n return goodSegment;\n}\n\n// Take a URL, and return the article base of said URL. That is, no\n// pagination data exists in it. Useful for comparing to other links\n// that might have pagination data within them.\nexport default function articleBaseUrl(url, parsed) {\n const parsedUrl = parsed || URL.parse(url);\n const { protocol, host, path } = parsedUrl;\n\n let firstSegmentHasLetters = false;\n const cleanedSegments = path.split('/')\n .reverse()\n .reduce((acc, rawSegment, index) => {\n let segment = rawSegment;\n\n // Split off and save anything that looks like a file type.\n if (segment.includes('.')) {\n const [possibleSegment, fileExt] = segment.split('.');\n if (IS_ALPHA_RE.test(fileExt)) {\n segment = possibleSegment;\n }\n }\n\n // If our first or second segment has anything looking like a page\n // number, remove it.\n if (PAGE_IN_HREF_RE.test(segment) && index < 2) {\n segment = segment.replace(PAGE_IN_HREF_RE, '');\n }\n\n // If we're on the first segment, check to see if we have any\n // characters in it. The first segment is actually the last bit of\n // the URL, and this will be helpful to determine if we're on a URL\n // segment that looks like \"/2/\" for example.\n if (index === 0) {\n firstSegmentHasLetters = HAS_ALPHA_RE.test(segment);\n }\n\n // If it's not marked for deletion, push it to cleaned_segments.\n if (isGoodSegment(segment, index, firstSegmentHasLetters)) {\n acc.push(segment);\n }\n\n return acc;\n }, []);\n\n return `${protocol}//${host}${cleanedSegments.reverse().join('/')}`;\n}\n","// Given a string, return True if it appears to have an ending sentence\n// within it, false otherwise.\nconst SENTENCE_END_RE = new RegExp('.( |$)');\nexport default function hasSentenceEnd(text) {\n return SENTENCE_END_RE.test(text);\n}\n\n","export default function excerptContent(content, words = 10) {\n return content.trim()\n .split(/\\s+/)\n .slice(0, words)\n .join(' ');\n}\n","import {\n textLength,\n linkDensity,\n} from 'utils/dom';\nimport { hasSentenceEnd } from 'utils/text';\n\nimport { NON_TOP_CANDIDATE_TAGS_RE } from './constants';\nimport { getScore } from './index';\n\n// Now that we have a top_candidate, look through the siblings of\n// it to see if any of them are decently scored. If they are, they\n// may be split parts of the content (Like two divs, a preamble and\n// a body.) Example:\n// http://articles.latimes.com/2009/oct/14/business/fi-bigtvs14\nexport default function mergeSiblings($candidate, topScore, $) {\n if (!$candidate.parent().length) {\n return $candidate;\n }\n\n const siblingScoreThreshold = Math.max(10, topScore * 0.25);\n const wrappingDiv = $('

');\n\n $candidate.parent().children().each((index, sibling) => {\n const $sibling = $(sibling);\n // Ignore tags like BR, HR, etc\n if (NON_TOP_CANDIDATE_TAGS_RE.test(sibling.tagName)) {\n return null;\n }\n\n const siblingScore = getScore($sibling);\n if (siblingScore) {\n if ($sibling === $candidate) {\n wrappingDiv.append($sibling);\n } else {\n let contentBonus = 0;\n const density = linkDensity($sibling);\n\n // If sibling has a very low link density,\n // give it a small bonus\n if (density < 0.05) {\n contentBonus += 20;\n }\n\n // If sibling has a high link density,\n // give it a penalty\n if (density >= 0.5) {\n contentBonus -= 20;\n }\n\n // If sibling node has the same class as\n // candidate, give it a bonus\n if ($sibling.attr('class') === $candidate.attr('class')) {\n contentBonus += topScore * 0.2;\n }\n\n const newScore = siblingScore + contentBonus;\n\n if (newScore >= siblingScoreThreshold) {\n return wrappingDiv.append($sibling);\n } else if (sibling.tagName === 'p') {\n const siblingContent = $sibling.text();\n const siblingContentLength = textLength(siblingContent);\n\n if (siblingContentLength > 80 && density < 0.25) {\n return wrappingDiv.append($sibling);\n } else if (siblingContentLength <= 80 && density === 0 &&\n hasSentenceEnd(siblingContent)) {\n return wrappingDiv.append($sibling);\n }\n }\n }\n }\n\n return null;\n });\n\n return wrappingDiv;\n}\n","import { NON_TOP_CANDIDATE_TAGS_RE } from './constants';\nimport { getScore } from './index';\nimport mergeSiblings from './merge-siblings';\n\n// After we've calculated scores, loop through all of the possible\n// candidate nodes we found and find the one with the highest score.\nexport default function findTopCandidate($) {\n let $candidate;\n let topScore = 0;\n\n $('[score]').each((index, node) => {\n // Ignore tags like BR, HR, etc\n if (NON_TOP_CANDIDATE_TAGS_RE.test(node.tagName)) {\n return;\n }\n\n const $node = $(node);\n const score = getScore($node);\n\n if (score > topScore) {\n topScore = score;\n $candidate = $node;\n }\n });\n\n // If we don't have a candidate, return the body\n // or whatever the first element is\n if (!$candidate) {\n return $('body') || $('*').first();\n }\n\n $candidate = mergeSiblings($candidate, topScore, $);\n\n return $candidate;\n}\n","import {\n getScore,\n setScore,\n getOrInitScore,\n scoreCommas,\n} from 'extractors/generic/content/scoring';\n\nimport { CLEAN_CONDITIONALLY_TAGS } from './constants';\nimport { normalizeSpaces } from '../text';\nimport { linkDensity } from './index';\n\nfunction removeUnlessContent($node, $, weight) {\n // Explicitly save entry-content-asset tags, which are\n // noted as valuable in the Publisher guidelines. For now\n // this works everywhere. We may want to consider making\n // this less of a sure-thing later.\n if ($node.hasClass('entry-content-asset')) {\n return;\n }\n\n const content = normalizeSpaces($node.text());\n\n if (scoreCommas(content) < 10) {\n const pCount = $('p', $node).length;\n const inputCount = $('input', $node).length;\n\n // Looks like a form, too many inputs.\n if (inputCount > (pCount / 3)) {\n $node.remove();\n return;\n }\n\n const contentLength = content.length;\n const imgCount = $('img', $node).length;\n\n // Content is too short, and there are no images, so\n // this is probably junk content.\n if (contentLength < 25 && imgCount === 0) {\n $node.remove();\n return;\n }\n\n const density = linkDensity($node);\n\n // Too high of link density, is probably a menu or\n // something similar.\n // console.log(weight, density, contentLength)\n if (weight < 25 && density > 0.2 && contentLength > 75) {\n $node.remove();\n return;\n }\n\n // Too high of a link density, despite the score being\n // high.\n if (weight >= 25 && density > 0.5) {\n // Don't remove the node if it's a list and the\n // previous sibling starts with a colon though. That\n // means it's probably content.\n const tagName = $node.get(0).tagName;\n const nodeIsList = tagName === 'ol' || tagName === 'ul';\n if (nodeIsList) {\n const previousNode = $node.prev();\n if (previousNode && normalizeSpaces(previousNode.text()).slice(-1) === ':') {\n return;\n }\n }\n\n $node.remove();\n return;\n }\n\n const scriptCount = $('script', $node).length;\n\n // Too many script tags, not enough content.\n if (scriptCount > 0 && contentLength < 150) {\n $node.remove();\n return;\n }\n }\n}\n\n// Given an article, clean it of some superfluous content specified by\n// tags. Things like forms, ads, etc.\n//\n// Tags is an array of tag name's to search through. (like div, form,\n// etc)\n//\n// Return this same doc.\nexport default function cleanTags($article, $) {\n $(CLEAN_CONDITIONALLY_TAGS, $article).each((index, node) => {\n const $node = $(node);\n let weight = getScore($node);\n if (!weight) {\n weight = getOrInitScore($node, $);\n setScore($node, $, weight);\n }\n\n // drop node if its weight is < 0\n if (weight < 0) {\n $node.remove();\n } else {\n // deteremine if node seems like content\n removeUnlessContent($node, $, weight);\n }\n });\n\n return $;\n}\n\n","import { getWeight } from 'extractors/generic/content/scoring';\n\nimport { HEADER_TAG_LIST } from './constants';\nimport { normalizeSpaces } from '../text';\n\nexport default function cleanHeaders($article, $, title = '') {\n $(HEADER_TAG_LIST, $article).each((index, header) => {\n const $header = $(header);\n // Remove any headers that appear before all other p tags in the\n // document. This probably means that it was part of the title, a\n // subtitle or something else extraneous like a datestamp or byline,\n // all of which should be handled by other metadata handling.\n if ($($header, $article).prevAll('p').length === 0) {\n return $header.remove();\n }\n\n // Remove any headers that match the title exactly.\n if (normalizeSpaces($(header).text()) === title) {\n return $header.remove();\n }\n\n // If this header has a negative weight, it's probably junk.\n // Get rid of it.\n if (getWeight($(header)) < 0) {\n return $header.remove();\n }\n\n return $header;\n });\n\n return $;\n}\n","import { convertNodeTo } from 'utils/dom';\n\n// Rewrite the tag name to div if it's a top level node like body or\n// html to avoid later complications with multiple body tags.\nexport default function rewriteTopLevel(article, $) {\n // I'm not using context here because\n // it's problematic when converting the\n // top-level/root node - AP\n $ = convertNodeTo($('html'), $, 'div');\n $ = convertNodeTo($('body'), $, 'div');\n\n return $;\n}\n","import URL from 'url';\n\nfunction absolutize($, rootUrl, attr, $content) {\n $(`[${attr}]`, $content).each((_, node) => {\n const url = node.attribs[attr];\n const absoluteUrl = URL.resolve(rootUrl, url);\n\n node.attribs[attr] = absoluteUrl;\n });\n}\n\nexport default function makeLinksAbsolute($content, $, url) {\n ['href', 'src'].forEach(attr => absolutize($, url, attr, $content));\n\n return $content;\n}\n","\nexport function textLength(text) {\n return text.trim()\n .replace(/\\s+/g, ' ')\n .length;\n}\n\n// Determines what percentage of the text\n// in a node is link text\n// Takes a node, returns a float\nexport function linkDensity($node) {\n const totalTextLength = textLength($node.text());\n\n const linkText = $node.find('a').text();\n const linkLength = textLength(linkText);\n\n if (totalTextLength > 0) {\n return linkLength / totalTextLength;\n } else if (totalTextLength === 0 && linkLength > 0) {\n return 1;\n }\n\n return 0;\n}\n","import { stripTags } from 'utils/dom';\n\n// Given a node type to search for, and a list of meta tag names to\n// search for, find a meta tag associated.\nexport default function extractFromMeta(\n $,\n metaNames,\n cachedNames,\n cleanTags = true\n) {\n const foundNames = metaNames.filter(name => cachedNames.indexOf(name) !== -1);\n\n for (const name of foundNames) {\n const type = 'name';\n const value = 'value';\n\n const nodes = $(`meta[${type}=\"${name}\"]`);\n\n // Get the unique value of every matching node, in case there\n // are two meta tags with the same name and value.\n // Remove empty values.\n const values =\n nodes.map((index, node) => $(node).attr(value))\n .toArray()\n .filter(text => text !== '');\n\n // If we have more than one value for the same name, we have a\n // conflict and can't trust any of them. Skip this name. If we have\n // zero, that means our meta tags had no values. Skip this name\n // also.\n if (values.length === 1) {\n let metaValue;\n // Meta values that contain HTML should be stripped, as they\n // weren't subject to cleaning previously.\n if (cleanTags) {\n metaValue = stripTags(values[0], $);\n } else {\n metaValue = values[0];\n }\n\n return metaValue;\n }\n }\n\n // If nothing is found, return null\n return null;\n}\n","import { withinComment } from 'utils/dom';\n\nfunction isGoodNode($node, maxChildren) {\n // If it has a number of children, it's more likely a container\n // element. Skip it.\n if ($node.children().length > maxChildren) {\n return false;\n }\n // If it looks to be within a comment, skip it.\n if (withinComment($node)) {\n return false;\n }\n\n return true;\n}\n\n// Given a a list of selectors find content that may\n// be extractable from the document. This is for flat\n// meta-information, like author, title, date published, etc.\nexport default function extractFromSelectors(\n $,\n selectors,\n maxChildren = 1,\n textOnly = true\n) {\n for (const selector of selectors) {\n const nodes = $(selector);\n\n // If we didn't get exactly one of this selector, this may be\n // a list of articles or comments. Skip it.\n if (nodes.length === 1) {\n const $node = $(nodes[0]);\n\n if (isGoodNode($node, maxChildren)) {\n let content;\n if (textOnly) {\n content = $node.text();\n } else {\n content = $node.html();\n }\n\n if (content) {\n return content;\n }\n }\n }\n }\n\n return null;\n}\n","// strips all tags from a string of text\nexport default function stripTags(text, $) {\n // Wrapping text in html element prevents errors when text\n // has no html\n const cleanText = $(`${text}`).text();\n return cleanText === '' ? text : cleanText;\n}\n","export default function withinComment($node) {\n const parents = $node.parents().toArray();\n const commentParent = parents.find((parent) => {\n const classAndId = `${parent.attribs.class} ${parent.attribs.id}`;\n return classAndId.includes('comment');\n });\n\n return commentParent !== undefined;\n}\n","// Given a node, determine if it's article-like enough to return\n// param: node (a cheerio node)\n// return: boolean\n\nexport default function nodeIsSufficient($node) {\n return $node.text().trim().length >= 100;\n}\n","import { IS_WP_SELECTOR } from './constants';\n\nexport default function isWordpress($) {\n return $(IS_WP_SELECTOR).length > 0;\n}\n","// CLEAN AUTHOR CONSTANTS\nexport const CLEAN_AUTHOR_RE = /^\\s*(posted |written )?by\\s*:?\\s*(.*)/i;\n // author = re.sub(r'^\\s*(posted |written )?by\\s*:?\\s*(.*)(?i)',\n\n// CLEAN DEK CONSTANTS\nexport const TEXT_LINK_RE = new RegExp('http(s)?://', 'i');\n// An ordered list of meta tag names that denote likely article deks.\n// From most distinct to least distinct.\n//\n// NOTE: There are currently no meta tags that seem to provide the right\n// content consistenty enough. Two options were:\n// - og:description\n// - dc.description\n// However, these tags often have SEO-specific junk in them that's not\n// header-worthy like a dek is. Excerpt material at best.\nexport const DEK_META_TAGS = [\n];\n\n// An ordered list of Selectors to find likely article deks. From\n// most explicit to least explicit.\n//\n// Should be more restrictive than not, as a failed dek can be pretty\n// detrimental to the aesthetics of an article.\nexport const DEK_SELECTORS = [\n '.entry-summary',\n];\n\n// CLEAN DATE PUBLISHED CONSTANTS\nexport const MS_DATE_STRING = /^\\d{13}$/i;\nexport const SEC_DATE_STRING = /^\\d{10}$/i;\nexport const CLEAN_DATE_STRING_RE = /^\\s*published\\s*:?\\s*(.*)/i;\nexport const TIME_MERIDIAN_SPACE_RE = /(.*\\d)(am|pm)(.*)/i;\nexport const TIME_MERIDIAN_DOTS_RE = /\\.m\\./i;\nconst months = [\n 'jan',\n 'feb',\n 'mar',\n 'apr',\n 'may',\n 'jun',\n 'jul',\n 'aug',\n 'sep',\n 'oct',\n 'nov',\n 'dec',\n];\nconst allMonths = months.join('|');\nconst timestamp1 = '[0-9]{1,2}:[0-9]{2,2}( ?[ap].?m.?)?';\nconst timestamp2 = '[0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4}';\nexport const SPLIT_DATE_STRING =\n new RegExp(`(${timestamp1})|(${timestamp2})|([0-9]{1,4})|(${allMonths})`, 'ig');\n\n// CLEAN TITLE CONSTANTS\n// A regular expression that will match separating characters on a\n// title, that usually denote breadcrumbs or something similar.\nexport const TITLE_SPLITTERS_RE = /(: | - | \\| )/g;\n\nexport const DOMAIN_ENDINGS_RE =\n new RegExp('.com$|.net$|.org$|.co.uk$', 'g');\n","import { CLEAN_AUTHOR_RE } from './constants';\n\n// Take an author string (like 'By David Smith ') and clean it to\n// just the name(s): 'David Smith'.\nexport default function cleanAuthor(author) {\n return author.replace(CLEAN_AUTHOR_RE, '$2').trim();\n}\n","import validUrl from 'valid-url';\n\nexport default function clean(leadImageUrl) {\n leadImageUrl = leadImageUrl.trim();\n if (validUrl.isWebUri(leadImageUrl)) {\n return leadImageUrl;\n }\n\n return null;\n}\n","import { stripTags } from 'utils/dom';\nimport { excerptContent } from 'utils/text';\n\nimport { TEXT_LINK_RE } from './constants';\n\n// Take a dek HTML fragment, and return the cleaned version of it.\n// Return None if the dek wasn't good enough.\nexport default function cleanDek(dek, { $, excerpt }) {\n // Sanity check that we didn't get too short or long of a dek.\n if (dek.length > 1000 || dek.length < 5) return null;\n\n // Check that dek isn't the same as excerpt\n if (excerpt && excerptContent(excerpt, 10) === excerptContent(dek, 10)) return null;\n\n const dekText = stripTags(dek, $);\n\n // Plain text links shouldn't exist in the dek. If we have some, it's\n // not a good dek - bail.\n if (TEXT_LINK_RE.test(dekText)) return null;\n\n return dekText.trim();\n}\n","import moment from 'moment';\n// Is there a compelling reason to use moment here?\n// Mostly only being used for the isValid() method,\n// but could just check for 'Invalid Date' string.\n\nimport {\n MS_DATE_STRING,\n SEC_DATE_STRING,\n CLEAN_DATE_STRING_RE,\n SPLIT_DATE_STRING,\n TIME_MERIDIAN_SPACE_RE,\n TIME_MERIDIAN_DOTS_RE,\n} from './constants';\n\nexport function cleanDateString(dateString) {\n return (dateString.match(SPLIT_DATE_STRING) || [])\n .join(' ')\n .replace(TIME_MERIDIAN_DOTS_RE, 'm')\n .replace(TIME_MERIDIAN_SPACE_RE, '$1 $2 $3')\n .replace(CLEAN_DATE_STRING_RE, '$1')\n .trim();\n}\n\n// Take a date published string, and hopefully return a date out of\n// it. Return none if we fail.\nexport default function cleanDatePublished(dateString) {\n // If string is in milliseconds or seconds, convert to int\n if (MS_DATE_STRING.test(dateString) || SEC_DATE_STRING.test(dateString)) {\n dateString = parseInt(dateString, 10);\n }\n\n let date = moment(new Date(dateString));\n\n if (!date.isValid()) {\n dateString = cleanDateString(dateString);\n date = moment(new Date(dateString));\n }\n\n return date.isValid() ? date.toISOString() : null;\n}\n","import {\n cleanAttributes,\n cleanHeaders,\n cleanHOnes,\n cleanImages,\n cleanTags,\n removeEmpty,\n rewriteTopLevel,\n markToKeep,\n stripJunkTags,\n makeLinksAbsolute,\n} from 'utils/dom';\n\n// Clean our article content, returning a new, cleaned node.\nexport default function extractCleanNode(\n article,\n {\n $,\n cleanConditionally = true,\n title = '',\n url = '',\n defaultCleaner = true,\n }\n) {\n // Rewrite the tag name to div if it's a top level node like body or\n // html to avoid later complications with multiple body tags.\n rewriteTopLevel(article, $);\n\n // Drop small images and spacer images\n // Only do this is defaultCleaner is set to true;\n // this can sometimes be too aggressive.\n if (defaultCleaner) cleanImages(article, $);\n\n // Mark elements to keep that would normally be removed.\n // E.g., stripJunkTags will remove iframes, so we're going to mark\n // YouTube/Vimeo videos as elements we want to keep.\n markToKeep(article, $, url);\n\n // Drop certain tags like , etc\n // This is -mostly- for cleanliness, not security.\n stripJunkTags(article, $);\n\n // H1 tags are typically the article title, which should be extracted\n // by the title extractor instead. If there's less than 3 of them (<3),\n // strip them. Otherwise, turn 'em into H2s.\n cleanHOnes(article, $);\n\n // Clean headers\n cleanHeaders(article, $, title);\n\n // Make links absolute\n makeLinksAbsolute(article, $, url);\n\n // We used to clean UL's and OL's here, but it was leading to\n // too many in-article lists being removed. Consider a better\n // way to detect menus particularly and remove them.\n // Also optionally running, since it can be overly aggressive.\n if (defaultCleaner) cleanTags(article, $, cleanConditionally);\n\n // Remove empty paragraph nodes\n removeEmpty(article, $);\n\n // Remove unnecessary attributes\n cleanAttributes(article, $);\n\n return article;\n}\n","import { stripTags } from 'utils/dom';\n\nimport { TITLE_SPLITTERS_RE } from './constants';\nimport { resolveSplitTitle } from './index';\n\nexport default function cleanTitle(title, { url, $ }) {\n // If title has |, :, or - in it, see if\n // we can clean it up.\n if (TITLE_SPLITTERS_RE.test(title)) {\n title = resolveSplitTitle(title, url);\n }\n\n // Final sanity check that we didn't get a crazy title.\n // if (title.length > 150 || title.length < 15) {\n if (title.length > 150) {\n // If we did, return h1 from the document if it exists\n const h1 = $('h1');\n if (h1.length === 1) {\n title = h1.text();\n }\n }\n\n // strip any html tags in the title text\n return stripTags(title, $).trim();\n}\n\n","import URL from 'url';\nimport wuzzy from 'wuzzy';\n\nimport {\n TITLE_SPLITTERS_RE,\n DOMAIN_ENDINGS_RE,\n} from './constants';\n\nfunction extractBreadcrumbTitle(splitTitle, text) {\n // This must be a very breadcrumbed title, like:\n // The Best Gadgets on Earth : Bits : Blogs : NYTimes.com\n // NYTimes - Blogs - Bits - The Best Gadgets on Earth\n if (splitTitle.length >= 6) {\n // Look to see if we can find a breadcrumb splitter that happens\n // more than once. If we can, we'll be able to better pull out\n // the title.\n const termCounts = splitTitle.reduce((acc, titleText) => {\n acc[titleText] = acc[titleText] ? acc[titleText] + 1 : 1;\n return acc;\n }, {});\n\n const [maxTerm, termCount] =\n Reflect.ownKeys(termCounts)\n .reduce((acc, key) => {\n if (acc[1] < termCounts[key]) {\n return [key, termCounts[key]];\n }\n\n return acc;\n }, [0, 0]);\n\n // We found a splitter that was used more than once, so it\n // is probably the breadcrumber. Split our title on that instead.\n // Note: max_term should be <= 4 characters, so that \" >> \"\n // will match, but nothing longer than that.\n if (termCount >= 2 && maxTerm.length <= 4) {\n splitTitle = text.split(maxTerm);\n }\n\n const splitEnds = [splitTitle[0], splitTitle.slice(-1)];\n const longestEnd = splitEnds.reduce((acc, end) => acc.length > end.length ? acc : end, '');\n\n if (longestEnd.length > 10) {\n return longestEnd;\n }\n\n return text;\n }\n\n return null;\n}\n\nfunction cleanDomainFromTitle(splitTitle, url) {\n // Search the ends of the title, looking for bits that fuzzy match\n // the URL too closely. If one is found, discard it and return the\n // rest.\n //\n // Strip out the big TLDs - it just makes the matching a bit more\n // accurate. Not the end of the world if it doesn't strip right.\n const { host } = URL.parse(url);\n const nakedDomain = host.replace(DOMAIN_ENDINGS_RE, '');\n\n const startSlug = splitTitle[0].toLowerCase().replace(' ', '');\n const startSlugRatio = wuzzy.levenshtein(startSlug, nakedDomain);\n\n if (startSlugRatio > 0.4 && startSlug.length > 5) {\n return splitTitle.slice(2).join('');\n }\n\n const endSlug = splitTitle.slice(-1)[0].toLowerCase().replace(' ', '');\n const endSlugRatio = wuzzy.levenshtein(endSlug, nakedDomain);\n\n if (endSlugRatio > 0.4 && endSlug.length >= 5) {\n return splitTitle.slice(0, -2).join('');\n }\n\n return null;\n}\n\n// Given a title with separators in it (colons, dashes, etc),\n// resolve whether any of the segments should be removed.\nexport default function resolveSplitTitle(title, url = '') {\n // Splits while preserving splitters, like:\n // ['The New New York', ' - ', 'The Washington Post']\n const splitTitle = title.split(TITLE_SPLITTERS_RE);\n if (splitTitle.length === 1) {\n return title;\n }\n\n let newTitle = extractBreadcrumbTitle(splitTitle, title);\n if (newTitle) return newTitle;\n\n newTitle = cleanDomainFromTitle(splitTitle, url);\n if (newTitle) return newTitle;\n\n // Fuzzy ratio didn't find anything, so this title is probably legit.\n // Just return it all.\n return title;\n}\n","import cleanAuthor from './author';\nimport cleanImage from './lead-image-url';\nimport cleanDek from './dek';\nimport cleanDatePublished from './date-published';\nimport cleanContent from './content';\nimport cleanTitle from './title';\n\nconst Cleaners = {\n author: cleanAuthor,\n lead_image_url: cleanImage,\n dek: cleanDek,\n date_published: cleanDatePublished,\n content: cleanContent,\n title: cleanTitle,\n};\n\n\nexport default Cleaners;\n\nexport { cleanAuthor };\nexport { cleanImage };\nexport { cleanDek };\nexport { cleanDatePublished };\nexport { cleanContent };\nexport { cleanTitle };\nexport { default as resolveSplitTitle } from './resolve-split-title';\n","import {\n stripUnlikelyCandidates,\n convertToParagraphs,\n} from 'utils/dom';\n\nimport {\n scoreContent,\n findTopCandidate,\n} from './scoring';\n\n// Using a variety of scoring techniques, extract the content most\n// likely to be article text.\n//\n// If strip_unlikely_candidates is True, remove any elements that\n// match certain criteria first. (Like, does this element have a\n// classname of \"comment\")\n//\n// If weight_nodes is True, use classNames and IDs to determine the\n// worthiness of nodes.\n//\n// Returns a cheerio object $\nexport default function extractBestNode($, opts) {\n // clone the node so we can get back to our\n // initial parsed state if needed\n // TODO Do I need this? – AP\n // let $root = $.root().clone()\n\n\n if (opts.stripUnlikelyCandidates) {\n $ = stripUnlikelyCandidates($);\n }\n\n $ = convertToParagraphs($);\n $ = scoreContent($, opts.weightNodes);\n const $topCandidate = findTopCandidate($);\n\n return $topCandidate;\n}\n","import cheerio from 'cheerio';\n\nimport { nodeIsSufficient } from 'utils/dom';\nimport { cleanContent } from 'cleaners';\nimport { normalizeSpaces } from 'utils/text';\n\nimport extractBestNode from './extract-best-node';\n\nconst GenericContentExtractor = {\n defaultOpts: {\n stripUnlikelyCandidates: true,\n weightNodes: true,\n cleanConditionally: true,\n },\n\n // Extract the content for this resource - initially, pass in our\n // most restrictive opts which will return the highest quality\n // content. On each failure, retry with slightly more lax opts.\n //\n // :param return_type: string. If \"node\", should return the content\n // as a cheerio node rather than as an HTML string.\n //\n // Opts:\n // stripUnlikelyCandidates: Remove any elements that match\n // non-article-like criteria first.(Like, does this element\n // have a classname of \"comment\")\n //\n // weightNodes: Modify an elements score based on whether it has\n // certain classNames or IDs. Examples: Subtract if a node has\n // a className of 'comment', Add if a node has an ID of\n // 'entry-content'.\n //\n // cleanConditionally: Clean the node to return of some\n // superfluous content. Things like forms, ads, etc.\n extract({ $, html, title, url }, opts) {\n opts = { ...this.defaultOpts, ...opts };\n\n $ = $ || cheerio.load(html);\n\n // Cascade through our extraction-specific opts in an ordered fashion,\n // turning them off as we try to extract content.\n let node = this.getContentNode($, title, url, opts);\n\n if (nodeIsSufficient(node)) {\n return this.cleanAndReturnNode(node, $);\n }\n\n // We didn't succeed on first pass, one by one disable our\n // extraction opts and try again.\n for (const key of Reflect.ownKeys(opts).filter(k => opts[k] === true)) {\n opts[key] = false;\n $ = cheerio.load(html);\n\n node = this.getContentNode($, title, url, opts);\n\n if (nodeIsSufficient(node)) {\n break;\n }\n }\n\n return this.cleanAndReturnNode(node, $);\n },\n\n // Get node given current options\n getContentNode($, title, url, opts) {\n return cleanContent(\n extractBestNode($, opts),\n {\n $,\n cleanConditionally: opts.cleanConditionally,\n title,\n url,\n });\n },\n\n // Once we got here, either we're at our last-resort node, or\n // we broke early. Make sure we at least have -something- before we\n // move forward.\n cleanAndReturnNode(node, $) {\n if (!node) {\n return null;\n }\n\n return normalizeSpaces($.html(node));\n\n // if return_type == \"html\":\n // return normalize_spaces(node_to_html(node))\n // else:\n // return node\n },\n\n};\n\nexport default GenericContentExtractor;\n","// TODO: It would be great if we could merge the meta and selector lists into\n// a list of objects, because we could then rank them better. For example,\n// .hentry .entry-title is far better suited than <meta title>.\n\n// An ordered list of meta tag names that denote likely article titles. All\n// attributes should be lowercase for faster case-insensitive matching. From\n// most distinct to least distinct.\nexport const STRONG_TITLE_META_TAGS = [\n 'tweetmeme-title',\n 'dc.title',\n 'rbtitle',\n 'headline',\n 'title',\n];\n\n// og:title is weak because it typically contains context that we don't like,\n// for example the source site's name. Gotta get that brand into facebook!\nexport const WEAK_TITLE_META_TAGS = [\n 'og:title',\n];\n\n// An ordered list of XPath Selectors to find likely article titles. From\n// most explicit to least explicit.\n//\n// Note - this does not use classes like CSS. This checks to see if the string\n// exists in the className, which is not as accurate as .className (which\n// splits on spaces/endlines), but for our purposes it's close enough. The\n// speed tradeoff is worth the accuracy hit.\nexport const STRONG_TITLE_SELECTORS = [\n '.hentry .entry-title',\n 'h1#articleHeader',\n 'h1.articleHeader',\n 'h1.article',\n '.instapaper_title',\n '#meebo-title',\n];\n\nexport const WEAK_TITLE_SELECTORS = [\n 'article h1',\n '#entry-title',\n '.entry-title',\n '#entryTitle',\n '#entrytitle',\n '.entryTitle',\n '.entrytitle',\n '#articleTitle',\n '.articleTitle',\n 'post post-title',\n 'h1.title',\n 'h2.article',\n 'h1',\n 'html head title',\n 'title',\n];\n","import { cleanTitle } from 'cleaners';\nimport {\n extractFromMeta,\n extractFromSelectors,\n} from 'utils/dom';\n\nimport {\n STRONG_TITLE_META_TAGS,\n WEAK_TITLE_META_TAGS,\n STRONG_TITLE_SELECTORS,\n WEAK_TITLE_SELECTORS,\n} from './constants';\n\nconst GenericTitleExtractor = {\n extract({ $, url, metaCache }) {\n // First, check to see if we have a matching meta tag that we can make\n // use of that is strongly associated with the headline.\n let title;\n\n title = extractFromMeta($, STRONG_TITLE_META_TAGS, metaCache);\n if (title) return cleanTitle(title, { url, $ });\n\n // Second, look through our content selectors for the most likely\n // article title that is strongly associated with the headline.\n title = extractFromSelectors($, STRONG_TITLE_SELECTORS);\n if (title) return cleanTitle(title, { url, $ });\n\n // Third, check for weaker meta tags that may match.\n title = extractFromMeta($, WEAK_TITLE_META_TAGS, metaCache);\n if (title) return cleanTitle(title, { url, $ });\n\n // Last, look for weaker selector tags that may match.\n title = extractFromSelectors($, WEAK_TITLE_SELECTORS);\n if (title) return cleanTitle(title, { url, $ });\n\n // If no matches, return an empty string\n return '';\n },\n};\n\nexport default GenericTitleExtractor;\n","// An ordered list of meta tag names that denote likely article authors. All\n// attributes should be lowercase for faster case-insensitive matching. From\n// most distinct to least distinct.\n//\n// Note: \"author\" is too often the -developer- of the page, so it is not\n// added here.\nexport const AUTHOR_META_TAGS = [\n 'byl',\n 'clmst',\n 'dc.author',\n 'dcsext.author',\n 'dc.creator',\n 'rbauthors',\n 'authors',\n];\n\nexport const AUTHOR_MAX_LENGTH = 300;\n\n// An ordered list of XPath Selectors to find likely article authors. From\n// most explicit to least explicit.\n//\n// Note - this does not use classes like CSS. This checks to see if the string\n// exists in the className, which is not as accurate as .className (which\n// splits on spaces/endlines), but for our purposes it's close enough. The\n// speed tradeoff is worth the accuracy hit.\nexport const AUTHOR_SELECTORS = [\n '.entry .entry-author',\n '.author.vcard .fn',\n '.author .vcard .fn',\n '.byline.vcard .fn',\n '.byline .vcard .fn',\n '.byline .by .author',\n '.byline .by',\n '.byline .author',\n '.post-author.vcard',\n '.post-author .vcard',\n 'a[rel=author]',\n '#by_author',\n '.by_author',\n '#entryAuthor',\n '.entryAuthor',\n '.byline a[href*=author]',\n '#author .authorname',\n '.author .authorname',\n '#author',\n '.author',\n '.articleauthor',\n '.ArticleAuthor',\n '.byline',\n];\n\n// An ordered list of Selectors to find likely article authors, with\n// regular expression for content.\nconst bylineRe = /^[\\n\\s]*By/i;\nexport const BYLINE_SELECTORS_RE = [\n ['#byline', bylineRe],\n ['.byline', bylineRe],\n];\n","import { cleanAuthor } from 'cleaners';\nimport {\n extractFromMeta,\n extractFromSelectors,\n} from 'utils/dom';\n\nimport {\n AUTHOR_META_TAGS,\n AUTHOR_MAX_LENGTH,\n AUTHOR_SELECTORS,\n BYLINE_SELECTORS_RE,\n} from './constants';\n\nconst GenericAuthorExtractor = {\n extract({ $, metaCache }) {\n let author;\n\n // First, check to see if we have a matching\n // meta tag that we can make use of.\n author = extractFromMeta($, AUTHOR_META_TAGS, metaCache);\n if (author && author.length < AUTHOR_MAX_LENGTH) {\n return cleanAuthor(author);\n }\n\n // Second, look through our selectors looking for potential authors.\n author = extractFromSelectors($, AUTHOR_SELECTORS, 2);\n if (author && author.length < AUTHOR_MAX_LENGTH) {\n return cleanAuthor(author);\n }\n\n // Last, use our looser regular-expression based selectors for\n // potential authors.\n for (const [selector, regex] of BYLINE_SELECTORS_RE) {\n const node = $(selector);\n if (node.length === 1) {\n const text = node.text();\n if (regex.test(text)) {\n return cleanAuthor(text);\n }\n }\n }\n\n return null;\n },\n};\n\nexport default GenericAuthorExtractor;\n\n","// An ordered list of meta tag names that denote\n// likely date published dates. All attributes\n// should be lowercase for faster case-insensitive matching.\n// From most distinct to least distinct.\nexport const DATE_PUBLISHED_META_TAGS = [\n 'article:published_time',\n 'displaydate',\n 'dc.date',\n 'dc.date.issued',\n 'rbpubdate',\n 'publish_date',\n 'pub_date',\n 'pagedate',\n 'pubdate',\n 'revision_date',\n 'doc_date',\n 'date_created',\n 'content_create_date',\n 'lastmodified',\n 'created',\n 'date',\n];\n\n// An ordered list of XPath Selectors to find\n// likely date published dates. From most explicit\n// to least explicit.\nexport const DATE_PUBLISHED_SELECTORS = [\n '.hentry .dtstamp.published',\n '.hentry .published',\n '.hentry .dtstamp.updated',\n '.hentry .updated',\n '.single .published',\n '.meta .published',\n '.meta .postDate',\n '.entry-date',\n '.byline .date',\n '.postmetadata .date',\n '.article_datetime',\n '.date-header',\n '.story-date',\n '.dateStamp',\n '#story .datetime',\n '.dateline',\n '.pubdate',\n];\n\n// An ordered list of compiled regular expressions to find likely date\n// published dates from the URL. These should always have the first\n// reference be a date string that is parseable by dateutil.parser.parse\nconst abbrevMonthsStr = '(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)';\nexport const DATE_PUBLISHED_URL_RES = [\n // /2012/01/27/ but not /2012/01/293\n new RegExp('/(20\\\\d{2}/\\\\d{2}/\\\\d{2})/', 'i'),\n // 20120127 or 20120127T but not 2012012733 or 8201201733\n // /[^0-9](20\\d{2}[01]\\d[0-3]\\d)([^0-9]|$)/i,\n // 2012-01-27\n new RegExp('(20\\\\d{2}-[01]\\\\d-[0-3]\\\\d)', 'i'),\n // /2012/jan/27/\n new RegExp(`/(20\\\\d{2}/${abbrevMonthsStr}/[0-3]\\\\d)/`, 'i'),\n];\n\n","import { cleanDatePublished } from 'cleaners';\nimport {\n extractFromMeta,\n extractFromSelectors,\n} from 'utils/dom';\nimport { extractFromUrl } from 'utils/text';\n\nimport {\n DATE_PUBLISHED_META_TAGS,\n DATE_PUBLISHED_SELECTORS,\n DATE_PUBLISHED_URL_RES,\n} from './constants';\n\nconst GenericDatePublishedExtractor = {\n extract({ $, url, metaCache }) {\n let datePublished;\n // First, check to see if we have a matching meta tag\n // that we can make use of.\n // Don't try cleaning tags from this string\n datePublished = extractFromMeta($, DATE_PUBLISHED_META_TAGS, metaCache, false);\n if (datePublished) return cleanDatePublished(datePublished);\n\n // Second, look through our selectors looking for potential\n // date_published's.\n datePublished = extractFromSelectors($, DATE_PUBLISHED_SELECTORS);\n if (datePublished) return cleanDatePublished(datePublished);\n\n // Lastly, look to see if a dately string exists in the URL\n datePublished = extractFromUrl(url, DATE_PUBLISHED_URL_RES);\n if (datePublished) return cleanDatePublished(datePublished);\n\n return null;\n },\n};\n\nexport default GenericDatePublishedExtractor;\n","// import {\n// DEK_META_TAGS,\n// DEK_SELECTORS,\n// DEK_URL_RES,\n// } from './constants';\n\n// import { cleanDek } from 'cleaners';\n\n// import {\n// extractFromMeta,\n// extractFromSelectors,\n// } from 'utils/dom';\n\n// Currently there is only one selector for\n// deks. We should simply return null here\n// until we have a more robust generic option.\n// Below is the original source for this, for reference.\nconst GenericDekExtractor = {\n // extract({ $, content, metaCache }) {\n extract() {\n return null;\n },\n};\n\nexport default GenericDekExtractor;\n\n// def extract_dek(self):\n// # First, check to see if we have a matching meta tag that we can make\n// # use of.\n// dek = self.extract_from_meta('dek', constants.DEK_META_TAGS)\n// if not dek:\n// # Second, look through our CSS/XPath selectors. This may return\n// # an HTML fragment.\n// dek = self.extract_from_selectors('dek',\n// constants.DEK_SELECTORS,\n// text_only=False)\n//\n// if dek:\n// # Make sure our dek isn't in the first few thousand characters\n// # of the content, otherwise it's just the start of the article\n// # and not a true dek.\n// content = self.extract_content()\n// content_chunk = normalize_spaces(strip_tags(content[:2000]))\n// dek_chunk = normalize_spaces(dek[:100]) # Already has no tags.\n//\n// # 80% or greater similarity means the dek was very similar to some\n// # of the starting content, so we skip it.\n// if fuzz.partial_ratio(content_chunk, dek_chunk) < 80:\n// return dek\n//\n// return None\n","// An ordered list of meta tag names that denote likely article leading images.\n// All attributes should be lowercase for faster case-insensitive matching.\n// From most distinct to least distinct.\nexport const LEAD_IMAGE_URL_META_TAGS = [\n 'og:image',\n 'twitter:image',\n 'image_src',\n];\n\nexport const LEAD_IMAGE_URL_SELECTORS = [\n 'link[rel=image_src]',\n];\n\nexport const POSITIVE_LEAD_IMAGE_URL_HINTS = [\n 'upload',\n 'wp-content',\n 'large',\n 'photo',\n 'wp-image',\n];\nexport const POSITIVE_LEAD_IMAGE_URL_HINTS_RE = new RegExp(POSITIVE_LEAD_IMAGE_URL_HINTS.join('|'), 'i');\n\nexport const NEGATIVE_LEAD_IMAGE_URL_HINTS = [\n 'spacer',\n 'sprite',\n 'blank',\n 'throbber',\n 'gradient',\n 'tile',\n 'bg',\n 'background',\n 'icon',\n 'social',\n 'header',\n 'hdr',\n 'advert',\n 'spinner',\n 'loader',\n 'loading',\n 'default',\n 'rating',\n 'share',\n 'facebook',\n 'twitter',\n 'theme',\n 'promo',\n 'ads',\n 'wp-includes',\n];\nexport const NEGATIVE_LEAD_IMAGE_URL_HINTS_RE = new RegExp(NEGATIVE_LEAD_IMAGE_URL_HINTS.join('|'), 'i');\n\nexport const GIF_RE = /\\.gif(\\?.*)?$/i;\nexport const JPG_RE = /\\.jpe?g(\\?.*)?$/i;\n","import {\n POSITIVE_LEAD_IMAGE_URL_HINTS_RE,\n NEGATIVE_LEAD_IMAGE_URL_HINTS_RE,\n GIF_RE,\n JPG_RE,\n} from './constants';\n\nimport { PHOTO_HINTS_RE } from '../content/scoring/constants';\n\nfunction getSig($node) {\n return `${$node.attr('class') || ''} ${$node.attr('id') || ''}`;\n}\n\n// Scores image urls based on a variety of heuristics.\nexport function scoreImageUrl(url) {\n url = url.trim();\n let score = 0;\n\n if (POSITIVE_LEAD_IMAGE_URL_HINTS_RE.test(url)) {\n score += 20;\n }\n\n if (NEGATIVE_LEAD_IMAGE_URL_HINTS_RE.test(url)) {\n score -= 20;\n }\n\n // TODO: We might want to consider removing this as\n // gifs are much more common/popular than they once were\n if (GIF_RE.test(url)) {\n score -= 10;\n }\n\n if (JPG_RE.test(url)) {\n score += 10;\n }\n\n // PNGs are neutral.\n\n return score;\n}\n\n// Alt attribute usually means non-presentational image.\nexport function scoreAttr($img) {\n if ($img.attr('alt')) {\n return 5;\n }\n\n return 0;\n}\n\n// Look through our parent and grandparent for figure-like\n// container elements, give a bonus if we find them\nexport function scoreByParents($img) {\n let score = 0;\n const $figParent = $img.parents('figure').first();\n\n if ($figParent.length === 1) {\n score += 25;\n }\n\n const $parent = $img.parent();\n let $gParent;\n if ($parent.length === 1) {\n $gParent = $parent.parent();\n }\n\n [$parent, $gParent].forEach(($node) => {\n if (PHOTO_HINTS_RE.test(getSig($node))) {\n score += 15;\n }\n });\n\n return score;\n}\n\n// Look at our immediate sibling and see if it looks like it's a\n// caption. Bonus if so.\nexport function scoreBySibling($img) {\n let score = 0;\n const $sibling = $img.next();\n const sibling = $sibling.get(0);\n\n if (sibling && sibling.tagName === 'figcaption') {\n score += 25;\n }\n\n if (PHOTO_HINTS_RE.test(getSig($sibling))) {\n score += 15;\n }\n\n return score;\n}\n\nexport function scoreByDimensions($img) {\n let score = 0;\n\n const width = parseFloat($img.attr('width'));\n const height = parseFloat($img.attr('height'));\n const src = $img.attr('src');\n\n // Penalty for skinny images\n if (width && width <= 50) {\n score -= 50;\n }\n\n // Penalty for short images\n if (height && height <= 50) {\n score -= 50;\n }\n\n if (width && height && !src.includes('sprite')) {\n const area = width * height;\n if (area < 5000) { // Smaller than 50 x 100\n score -= 100;\n } else {\n score += Math.round(area / 1000);\n }\n }\n\n return score;\n}\n\nexport function scoreByPosition($imgs, index) {\n return ($imgs.length / 2) - index;\n}\n","import { extractFromMeta } from 'utils/dom';\nimport { cleanImage } from 'cleaners';\n\nimport {\n LEAD_IMAGE_URL_META_TAGS,\n LEAD_IMAGE_URL_SELECTORS,\n} from './constants';\n\nimport {\n scoreImageUrl,\n scoreAttr,\n scoreByParents,\n scoreBySibling,\n scoreByDimensions,\n scoreByPosition,\n} from './score-image';\n\n// Given a resource, try to find the lead image URL from within\n// it. Like content and next page extraction, uses a scoring system\n// to determine what the most likely image may be. Short circuits\n// on really probable things like og:image meta tags.\n//\n// Potential signals to still take advantage of:\n// * domain\n// * weird aspect ratio\nconst GenericLeadImageUrlExtractor = {\n extract({ $, content, metaCache }) {\n let cleanUrl;\n\n // Check to see if we have a matching meta tag that we can make use of.\n // Moving this higher because common practice is now to use large\n // images on things like Open Graph or Twitter cards.\n // images usually have for things like Open Graph.\n const imageUrl =\n extractFromMeta(\n $,\n LEAD_IMAGE_URL_META_TAGS,\n metaCache,\n false\n );\n\n if (imageUrl) {\n cleanUrl = cleanImage(imageUrl);\n\n if (cleanUrl) return cleanUrl;\n }\n\n // Next, try to find the \"best\" image via the content.\n // We'd rather not have to fetch each image and check dimensions,\n // so try to do some analysis and determine them instead.\n const imgs = $('img', content).toArray();\n const imgScores = {};\n\n imgs.forEach((img, index) => {\n const $img = $(img);\n const src = $img.attr('src');\n\n if (!src) return;\n\n let score = scoreImageUrl(src);\n score += scoreAttr($img);\n score += scoreByParents($img);\n score += scoreBySibling($img);\n score += scoreByDimensions($img);\n score += scoreByPosition(imgs, index);\n\n imgScores[src] = score;\n });\n\n const [topUrl, topScore] =\n Reflect.ownKeys(imgScores).reduce((acc, key) =>\n imgScores[key] > acc[1] ? [key, imgScores[key]] : acc\n , [null, 0]);\n\n if (topScore > 0) {\n cleanUrl = cleanImage(topUrl);\n\n if (cleanUrl) return cleanUrl;\n }\n\n // If nothing else worked, check to see if there are any really\n // probable nodes in the doc, like <link rel=\"image_src\" />.\n for (const selector of LEAD_IMAGE_URL_SELECTORS) {\n const $node = $(selector).first();\n const src = $node.attr('src');\n if (src) {\n cleanUrl = cleanImage(src);\n if (cleanUrl) return cleanUrl;\n }\n\n const href = $node.attr('href');\n if (href) {\n cleanUrl = cleanImage(href);\n if (cleanUrl) return cleanUrl;\n }\n\n const value = $node.attr('value');\n if (value) {\n cleanUrl = cleanImage(value);\n if (cleanUrl) return cleanUrl;\n }\n }\n\n return null;\n },\n};\n\nexport default GenericLeadImageUrlExtractor;\n\n// def extract(self):\n// \"\"\"\n// # First, try to find the \"best\" image via the content.\n// # We'd rather not have to fetch each image and check dimensions,\n// # so try to do some analysis and determine them instead.\n// content = self.extractor.extract_content(return_type=\"node\")\n// imgs = content.xpath('.//img')\n// img_scores = defaultdict(int)\n// logger.debug('Scoring %d images from content', len(imgs))\n// for (i, img) in enumerate(imgs):\n// img_score = 0\n//\n// if not 'src' in img.attrib:\n// logger.debug('No src attribute found')\n// continue\n//\n// try:\n// parsed_img = urlparse(img.attrib['src'])\n// img_path = parsed_img.path.lower()\n// except ValueError:\n// logger.debug('ValueError getting img path.')\n// continue\n// logger.debug('Image path is %s', img_path)\n//\n// if constants.POSITIVE_LEAD_IMAGE_URL_HINTS_RE.match(img_path):\n// logger.debug('Positive URL hints match. Adding 20.')\n// img_score += 20\n//\n// if constants.NEGATIVE_LEAD_IMAGE_URL_HINTS_RE.match(img_path):\n// logger.debug('Negative URL hints match. Subtracting 20.')\n// img_score -= 20\n//\n// # Gifs are more often structure than photos\n// if img_path.endswith('gif'):\n// logger.debug('gif found. Subtracting 10.')\n// img_score -= 10\n//\n// # JPGs are more often photographs\n// if img_path.endswith('jpg'):\n// logger.debug('jpg found. Adding 10.')\n// img_score += 10\n//\n// # PNGs are neutral.\n//\n// # Alt attribute usually means non-presentational image.\n// if 'alt' in img.attrib and len(img.attrib['alt']) > 5:\n// logger.debug('alt attribute found. Adding 5.')\n// img_score += 5\n//\n// # Look through our parent and grandparent for figure-like\n// # container elements, give a bonus if we find them\n// parents = [img.getparent()]\n// if parents[0] is not None and parents[0].getparent() is not None:\n// parents.append(parents[0].getparent())\n// for p in parents:\n// if p.tag == 'figure':\n// logger.debug('Parent with <figure> tag found. Adding 25.')\n// img_score += 25\n//\n// p_sig = ' '.join([p.get('id', ''), p.get('class', '')])\n// if constants.PHOTO_HINTS_RE.search(p_sig):\n// logger.debug('Photo hints regex match. Adding 15.')\n// img_score += 15\n//\n// # Look at our immediate sibling and see if it looks like it's a\n// # caption. Bonus if so.\n// sibling = img.getnext()\n// if sibling is not None:\n// if sibling.tag == 'figcaption':\n// img_score += 25\n//\n// sib_sig = ' '.join([sibling.get('id', ''),\n// sibling.get('class', '')]).lower()\n// if 'caption' in sib_sig:\n// img_score += 15\n//\n// # Pull out width/height if they were set.\n// img_width = None\n// img_height = None\n// if 'width' in img.attrib:\n// try:\n// img_width = float(img.get('width'))\n// except ValueError:\n// pass\n// if 'height' in img.attrib:\n// try:\n// img_height = float(img.get('height'))\n// except ValueError:\n// pass\n//\n// # Penalty for skinny images\n// if img_width and img_width <= 50:\n// logger.debug('Skinny image found. Subtracting 50.')\n// img_score -= 50\n//\n// # Penalty for short images\n// if img_height and img_height <= 50:\n// # Wide, short images are more common than narrow, tall ones\n// logger.debug('Short image found. Subtracting 25.')\n// img_score -= 25\n//\n// if img_width and img_height and not 'sprite' in img_path:\n// area = img_width * img_height\n//\n// if area < 5000: # Smaller than 50x100\n// logger.debug('Image with small area found. Subtracting 100.')\n// img_score -= 100\n// else:\n// img_score += round(area/1000.0)\n//\n// # If the image is higher on the page than other images,\n// # it gets a bonus. Penalty if lower.\n// logger.debug('Adding page placement bonus of %d.', len(imgs)/2 - i)\n// img_score += len(imgs)/2 - i\n//\n// # Use the raw src here because we munged img_path for case\n// # insensitivity\n// logger.debug('Final score is %d.', img_score)\n// img_scores[img.attrib['src']] += img_score\n//\n// top_score = 0\n// top_url = None\n// for (url, score) in img_scores.items():\n// if score > top_score:\n// top_url = url\n// top_score = score\n//\n// if top_score > 0:\n// logger.debug('Using top score image from content. Score was %d', top_score)\n// return top_url\n//\n//\n// # If nothing else worked, check to see if there are any really\n// # probable nodes in the doc, like <link rel=\"image_src\" />.\n// logger.debug('Trying to find lead image in probable nodes')\n// for selector in constants.LEAD_IMAGE_URL_SELECTORS:\n// nodes = self.resource.extract_by_selector(selector)\n// for node in nodes:\n// clean_value = None\n// if node.attrib.get('src'):\n// clean_value = self.clean(node.attrib['src'])\n//\n// if not clean_value and node.attrib.get('href'):\n// clean_value = self.clean(node.attrib['href'])\n//\n// if not clean_value and node.attrib.get('value'):\n// clean_value = self.clean(node.attrib['value'])\n//\n// if clean_value:\n// logger.debug('Found lead image in probable nodes.')\n// logger.debug('Node was: %s', node)\n// return clean_value\n//\n// return None\n","import difflib from 'difflib';\n\nexport default function scoreSimilarity(score, articleUrl, href) {\n // Do this last and only if we have a real candidate, because it's\n // potentially expensive computationally. Compare the link to this\n // URL using difflib to get the % similarity of these URLs. On a\n // sliding scale, subtract points from this link based on\n // similarity.\n if (score > 0) {\n const similarity = new difflib.SequenceMatcher(null, articleUrl, href).ratio();\n // Subtract .1 from diff_percent when calculating modifier,\n // which means that if it's less than 10% different, we give a\n // bonus instead. Ex:\n // 3% different = +17.5 points\n // 10% different = 0 points\n // 20% different = -25 points\n const diffPercent = 1.0 - similarity;\n const diffModifier = -(250 * (diffPercent - 0.2));\n return score + diffModifier;\n }\n\n return 0;\n}\n","import { IS_DIGIT_RE } from 'utils/text/constants';\n\nexport default function scoreLinkText(linkText, pageNum) {\n // If the link text can be parsed as a number, give it a minor\n // bonus, with a slight bias towards lower numbered pages. This is\n // so that pages that might not have 'next' in their text can still\n // get scored, and sorted properly by score.\n let score = 0;\n\n if (IS_DIGIT_RE.test(linkText.trim())) {\n const linkTextAsNum = parseInt(linkText, 10);\n // If it's the first page, we already got it on the first call.\n // Give it a negative score. Otherwise, up to page 10, give a\n // small bonus.\n if (linkTextAsNum < 2) {\n score = -30;\n } else {\n score = Math.max(0, 10 - linkTextAsNum);\n }\n\n // If it appears that the current page number is greater than\n // this links page number, it's a very bad sign. Give it a big\n // penalty.\n if (pageNum && pageNum >= linkTextAsNum) {\n score -= 50;\n }\n }\n\n return score;\n}\n","export default function scorePageInLink(pageNum, isWp) {\n // page in the link = bonus. Intentionally ignore wordpress because\n // their ?p=123 link style gets caught by this even though it means\n // separate documents entirely.\n if (pageNum && !isWp) {\n return 50;\n }\n\n return 0;\n}\n","export const DIGIT_RE = /\\d/;\n\n// A list of words that, if found in link text or URLs, likely mean that\n// this link is not a next page link.\nexport const EXTRANEOUS_LINK_HINTS = [\n 'print',\n 'archive',\n 'comment',\n 'discuss',\n 'e-mail',\n 'email',\n 'share',\n 'reply',\n 'all',\n 'login',\n 'sign',\n 'single',\n 'adx',\n 'entry-unrelated',\n];\nexport const EXTRANEOUS_LINK_HINTS_RE = new RegExp(EXTRANEOUS_LINK_HINTS.join('|'), 'i');\n\n// Match any link text/classname/id that looks like it could mean the next\n// page. Things like: next, continue, >, >>, » but not >|, »| as those can\n// mean last page.\nexport const NEXT_LINK_TEXT_RE = new RegExp('(next|weiter|continue|>([^|]|$)|»([^|]|$))', 'i');\n\n// Match any link text/classname/id that looks like it is an end link: things\n// like \"first\", \"last\", \"end\", etc.\nexport const CAP_LINK_TEXT_RE = new RegExp('(first|last|end)', 'i');\n\n// Match any link text/classname/id that looks like it means the previous\n// page.\nexport const PREV_LINK_TEXT_RE = new RegExp('(prev|earl|old|new|<|«)', 'i');\n\n// Match any phrase that looks like it could be page, or paging, or pagination\nexport const PAGE_RE = new RegExp('pag(e|ing|inat)', 'i');\n\n","import { EXTRANEOUS_LINK_HINTS_RE } from '../constants';\n\nexport default function scoreExtraneousLinks(href) {\n // If the URL itself contains extraneous values, give a penalty.\n if (EXTRANEOUS_LINK_HINTS_RE.test(href)) {\n return -25;\n }\n\n return 0;\n}\n","import { range } from 'utils';\nimport {\n NEGATIVE_SCORE_RE,\n POSITIVE_SCORE_RE,\n PAGE_RE,\n} from 'utils/dom/constants';\nimport { EXTRANEOUS_LINK_HINTS_RE } from '../constants';\n\nfunction makeSig($link) {\n return `${$link.attr('class') || ''} ${$link.attr('id') || ''}`;\n}\n\nexport default function scoreByParents($link) {\n // If a parent node contains paging-like classname or id, give a\n // bonus. Additionally, if a parent_node contains bad content\n // (like 'sponsor'), give a penalty.\n let $parent = $link.parent();\n let positiveMatch = false;\n let negativeMatch = false;\n let score = 0;\n\n Array.from(range(0, 4)).forEach(() => {\n if ($parent.length === 0) {\n return;\n }\n\n const parentData = makeSig($parent, ' ');\n\n // If we have 'page' or 'paging' in our data, that's a good\n // sign. Add a bonus.\n if (!positiveMatch && PAGE_RE.test(parentData)) {\n positiveMatch = true;\n score += 25;\n }\n\n // If we have 'comment' or something in our data, and\n // we don't have something like 'content' as well, that's\n // a bad sign. Give a penalty.\n if (!negativeMatch && NEGATIVE_SCORE_RE.test(parentData)\n && EXTRANEOUS_LINK_HINTS_RE.test(parentData)) {\n if (!POSITIVE_SCORE_RE.test(parentData)) {\n negativeMatch = true;\n score -= 25;\n }\n }\n\n $parent = $parent.parent();\n });\n\n return score;\n}\n\n","import { PREV_LINK_TEXT_RE } from '../constants';\n\nexport default function scorePrevLink(linkData) {\n // If the link has something like \"previous\", its definitely\n // an old link, skip it.\n if (PREV_LINK_TEXT_RE.test(linkData)) {\n return -200;\n }\n\n return 0;\n}\n","import URL from 'url';\n\nimport {\n DIGIT_RE,\n EXTRANEOUS_LINK_HINTS_RE,\n} from '../constants';\n\nexport default function shouldScore(\n href,\n articleUrl,\n baseUrl,\n parsedUrl,\n linkText,\n previousUrls\n) {\n // skip if we've already fetched this url\n if (previousUrls.find(url => href === url) !== undefined) {\n return false;\n }\n\n // If we've already parsed this URL, or the URL matches the base\n // URL, or is empty, skip it.\n if (!href || href === articleUrl || href === baseUrl) {\n return false;\n }\n\n const { hostname } = parsedUrl;\n const { hostname: linkHost } = URL.parse(href);\n\n // Domain mismatch.\n if (linkHost !== hostname) {\n return false;\n }\n\n // If href doesn't contain a digit after removing the base URL,\n // it's certainly not the next page.\n const fragment = href.replace(baseUrl, '');\n if (!DIGIT_RE.test(fragment)) {\n return false;\n }\n\n // This link has extraneous content (like \"comment\") in its link\n // text, so we skip it.\n if (EXTRANEOUS_LINK_HINTS_RE.test(linkText)) {\n return false;\n }\n\n // Next page link text is never long, skip if it is too long.\n if (linkText.length > 25) {\n return false;\n }\n\n return true;\n}\n\n","export default function scoreBaseUrl(href, baseRegex) {\n // If the baseUrl isn't part of this URL, penalize this\n // link. It could still be the link, but the odds are lower.\n // Example:\n // http://www.actionscript.org/resources/articles/745/1/JavaScript-and-VBScript-Injection-in-ActionScript-3/Page1.html\n if (!baseRegex.test(href)) {\n return -25;\n }\n\n return 0;\n}\n","import { NEXT_LINK_TEXT_RE } from '../constants';\n\nexport default function scoreNextLinkText(linkData) {\n // Things like \"next\", \">>\", etc.\n if (NEXT_LINK_TEXT_RE.test(linkData)) {\n return 50;\n }\n\n return 0;\n}\n","import {\n NEXT_LINK_TEXT_RE,\n CAP_LINK_TEXT_RE,\n} from '../constants';\n\nexport default function scoreCapLinks(linkData) {\n // Cap links are links like \"last\", etc.\n if (CAP_LINK_TEXT_RE.test(linkData)) {\n // If we found a link like \"last\", but we've already seen that\n // this link is also \"next\", it's fine. If it's not been\n // previously marked as \"next\", then it's probably bad.\n // Penalize.\n if (NEXT_LINK_TEXT_RE.test(linkData)) {\n return -65;\n }\n }\n\n return 0;\n}\n","import URL from 'url';\n\nimport { isWordpress } from 'utils/dom';\nimport {\n removeAnchor,\n pageNumFromUrl,\n} from 'utils/text';\n\nimport {\n scoreSimilarity,\n scoreLinkText,\n scorePageInLink,\n scoreExtraneousLinks,\n scoreByParents,\n scorePrevLink,\n shouldScore,\n scoreBaseUrl,\n scoreCapLinks,\n scoreNextLinkText,\n} from './utils';\n\nexport function makeBaseRegex(baseUrl) {\n return new RegExp(`^${baseUrl}`, 'i');\n}\n\nfunction makeSig($link, linkText) {\n return `${linkText || $link.text()} ${$link.attr('class') || ''} ${$link.attr('id') || ''}`;\n}\n\nexport default function scoreLinks({\n links,\n articleUrl,\n baseUrl,\n parsedUrl,\n $,\n previousUrls = [],\n}) {\n parsedUrl = parsedUrl || URL.parse(articleUrl);\n const baseRegex = makeBaseRegex(baseUrl);\n const isWp = isWordpress($);\n\n // Loop through all links, looking for hints that they may be next-page\n // links. Things like having \"page\" in their textContent, className or\n // id, or being a child of a node with a page-y className or id.\n //\n // After we do that, assign each page a score, and pick the one that\n // looks most like the next page link, as long as its score is strong\n // enough to have decent confidence.\n const scoredPages = links.reduce((possiblePages, link) => {\n // Remove any anchor data since we don't do a good job\n // standardizing URLs (it's hard), we're going to do\n // some checking with and without a trailing slash\n const href = removeAnchor(link.attribs.href);\n const $link = $(link);\n const linkText = $link.text();\n\n if (!shouldScore(href, articleUrl, baseUrl, parsedUrl, linkText, previousUrls)) {\n return possiblePages;\n }\n\n // ## PASSED THE FIRST-PASS TESTS. Start scoring. ##\n if (!possiblePages[href]) {\n possiblePages[href] = {\n score: 0,\n linkText,\n href,\n };\n } else {\n possiblePages[href].linkText = `${possiblePages[href].linkText}|${linkText}`;\n }\n\n const possiblePage = possiblePages[href];\n const linkData = makeSig($link, linkText);\n const pageNum = pageNumFromUrl(href);\n\n let score = scoreBaseUrl(href, baseRegex);\n score += scoreNextLinkText(linkData);\n score += scoreCapLinks(linkData);\n score += scorePrevLink(linkData);\n score += scoreByParents($link);\n score += scoreExtraneousLinks(href);\n score += scorePageInLink(pageNum, isWp);\n score += scoreLinkText(linkText, pageNum);\n score += scoreSimilarity(score, articleUrl, href);\n\n possiblePage.score = score;\n\n return possiblePages;\n }, {});\n\n return Reflect.ownKeys(scoredPages).length === 0 ? null : scoredPages;\n}\n","import URL from 'url';\n\nimport {\n articleBaseUrl,\n removeAnchor,\n} from 'utils/text';\nimport scoreLinks from './scoring/score-links';\n\n// Looks for and returns next page url\n// for multi-page articles\nconst GenericNextPageUrlExtractor = {\n extract({ $, url, parsedUrl, previousUrls = [] }) {\n parsedUrl = parsedUrl || URL.parse(url);\n\n const articleUrl = removeAnchor(url);\n const baseUrl = articleBaseUrl(url, parsedUrl);\n\n const links = $('a[href]').toArray();\n\n const scoredLinks = scoreLinks({\n links,\n articleUrl,\n baseUrl,\n parsedUrl,\n $,\n previousUrls,\n });\n\n // If no links were scored, return null\n if (!scoredLinks) return null;\n\n // now that we've scored all possible pages,\n // find the biggest one.\n const topPage = Reflect.ownKeys(scoredLinks).reduce((acc, link) => {\n const scoredLink = scoredLinks[link];\n return scoredLink.score > acc.score ? scoredLink : acc;\n }, { score: -100 });\n\n // If the score is less than 50, we're not confident enough to use it,\n // so we fail.\n if (topPage.score >= 50) {\n return topPage.href;\n }\n\n return null;\n },\n};\n\n\nexport default GenericNextPageUrlExtractor;\n","export const CANONICAL_META_SELECTORS = [\n 'og:url',\n];\n","import URL from 'url';\nimport { extractFromMeta } from 'utils/dom';\n\nimport { CANONICAL_META_SELECTORS } from './constants';\n\nfunction parseDomain(url) {\n const parsedUrl = URL.parse(url);\n const { hostname } = parsedUrl;\n return hostname;\n}\n\nfunction result(url) {\n return {\n url,\n domain: parseDomain(url),\n };\n}\n\nconst GenericUrlExtractor = {\n extract({ $, url, metaCache }) {\n const $canonical = $('link[rel=canonical]');\n if ($canonical.length !== 0) {\n const href = $canonical.attr('href');\n if (href) {\n return result(href);\n }\n }\n\n const metaUrl = extractFromMeta($, CANONICAL_META_SELECTORS, metaCache);\n if (metaUrl) {\n return result(metaUrl);\n }\n\n return result(url);\n },\n\n};\n\nexport default GenericUrlExtractor;\n","export const EXCERPT_META_SELECTORS = [\n 'og:description',\n 'twitter:description',\n];\n","import ellipsize from 'ellipsize';\n\nimport {\n extractFromMeta,\n stripTags,\n} from 'utils/dom';\n\nimport { EXCERPT_META_SELECTORS } from './constants';\n\nexport function clean(content, $, maxLength = 200) {\n content = content.replace(/[\\s\\n]+/g, ' ').trim();\n return ellipsize(content, maxLength, { ellipse: '…' });\n}\n\nconst GenericExcerptExtractor = {\n extract({ $, content, metaCache }) {\n const excerpt = extractFromMeta($, EXCERPT_META_SELECTORS, metaCache);\n if (excerpt) {\n return clean(stripTags(excerpt, $));\n }\n // Fall back to excerpting from the extracted content\n const maxLength = 200;\n const shortContent = content.slice(0, maxLength * 5);\n return clean($(shortContent).text(), $, maxLength);\n },\n};\n\nexport default GenericExcerptExtractor;\n","import cheerio from 'cheerio';\n\nimport { normalizeSpaces } from 'utils/text';\n\nconst GenericWordCountExtractor = {\n extract({ content }) {\n const $ = cheerio.load(content);\n\n const text = normalizeSpaces($('div').first().text());\n return text.split(/\\s/).length;\n },\n};\n\nexport default GenericWordCountExtractor;\n","import cheerio from 'cheerio';\nimport stringDirection from 'string-direction';\n\nimport GenericContentExtractor from './content/extractor';\nimport GenericTitleExtractor from './title/extractor';\nimport GenericAuthorExtractor from './author/extractor';\nimport GenericDatePublishedExtractor from './date-published/extractor';\nimport GenericDekExtractor from './dek/extractor';\nimport GenericLeadImageUrlExtractor from './lead-image-url/extractor';\nimport GenericNextPageUrlExtractor from './next-page-url/extractor';\nimport GenericUrlExtractor from './url/extractor';\nimport GenericExcerptExtractor from './excerpt/extractor';\nimport GenericWordCountExtractor from './word-count/extractor';\n\nconst GenericExtractor = {\n // This extractor is the default for all domains\n domain: '*',\n title: GenericTitleExtractor.extract,\n date_published: GenericDatePublishedExtractor.extract,\n author: GenericAuthorExtractor.extract,\n content: GenericContentExtractor.extract.bind(GenericContentExtractor),\n lead_image_url: GenericLeadImageUrlExtractor.extract,\n dek: GenericDekExtractor.extract,\n next_page_url: GenericNextPageUrlExtractor.extract,\n url_and_domain: GenericUrlExtractor.extract,\n excerpt: GenericExcerptExtractor.extract,\n word_count: GenericWordCountExtractor.extract,\n direction: ({ title }) => stringDirection.getDirection(title),\n\n extract(options) {\n const { html } = options;\n\n if (html) {\n const $ = cheerio.load(html);\n options.$ = $;\n }\n\n const title = this.title(options);\n const date_published = this.date_published(options);\n const author = this.author(options);\n const content = this.content({ ...options, title });\n const lead_image_url = this.lead_image_url({ ...options, content });\n const dek = this.dek({ ...options, content });\n const next_page_url = this.next_page_url(options);\n const excerpt = this.excerpt({ ...options, content });\n const word_count = this.word_count({ ...options, content });\n const direction = this.direction({ title });\n const { url, domain } = this.url_and_domain(options);\n\n return {\n title,\n author,\n date_published: date_published || null,\n dek,\n lead_image_url,\n content,\n next_page_url,\n url,\n domain,\n excerpt,\n word_count,\n direction,\n };\n },\n};\n\nexport default GenericExtractor;\n","import URL from 'url';\n\nimport Extractors from './all';\nimport GenericExtractor from './generic';\n\nexport default function getExtractor(url, parsedUrl) {\n parsedUrl = parsedUrl || URL.parse(url);\n const { hostname } = parsedUrl;\n const baseDomain = hostname.split('.').slice(-2).join('.');\n\n return Extractors[hostname] || Extractors[baseDomain] || GenericExtractor;\n}\n","import Cleaners from 'cleaners';\nimport { convertNodeTo } from 'utils/dom';\nimport GenericExtractor from './generic';\n\n// Remove elements by an array of selectors\nexport function cleanBySelectors($content, $, { clean }) {\n if (!clean) return $content;\n\n $(clean.join(','), $content).remove();\n\n return $content;\n}\n\n// Transform matching elements\nexport function transformElements($content, $, { transforms }) {\n if (!transforms) return $content;\n\n Reflect.ownKeys(transforms).forEach((key) => {\n const $matches = $(key, $content);\n const value = transforms[key];\n\n // If value is a string, convert directly\n if (typeof value === 'string') {\n $matches.each((index, node) => {\n convertNodeTo($(node), $, transforms[key]);\n });\n } else if (typeof value === 'function') {\n // If value is function, apply function to node\n $matches.each((index, node) => {\n const result = value($(node), $);\n // If function returns a string, convert node to that value\n if (typeof result === 'string') {\n convertNodeTo($(node), $, result);\n }\n });\n }\n });\n\n return $content;\n}\n\nfunction findMatchingSelector($, selectors) {\n return selectors.find((selector) => {\n if (Array.isArray(selector)) {\n const [s, attr] = selector;\n return $(s).length === 1 && $(s).attr(attr) && $(s).attr(attr).trim() !== '';\n }\n\n return $(selector).length === 1 && $(selector).text().trim() !== '';\n });\n}\n\nexport function select(opts) {\n const { $, type, extractionOpts, extractHtml = false } = opts;\n // Skip if there's not extraction for this type\n if (!extractionOpts) return null;\n\n // If a string is hardcoded for a type (e.g., Wikipedia\n // contributors), return the string\n if (typeof extractionOpts === 'string') return extractionOpts;\n\n const { selectors, defaultCleaner = true } = extractionOpts;\n\n const matchingSelector = findMatchingSelector($, selectors);\n\n if (!matchingSelector) return null;\n\n // Declaring result; will contain either\n // text or html, which will be cleaned\n // by the appropriate cleaner type\n\n // If the selector type requests html as its return type\n // transform and clean the element with provided selectors\n if (extractHtml) {\n let $content = $(matchingSelector);\n\n // Wrap in div so transformation can take place on root element\n $content.wrap($('<div></div>'));\n $content = $content.parent();\n\n $content = transformElements($content, $, extractionOpts);\n $content = cleanBySelectors($content, $, extractionOpts);\n\n $content = Cleaners[type]($content, { ...opts, defaultCleaner });\n\n return $.html($content);\n }\n\n let result;\n\n // if selector is an array (e.g., ['img', 'src']),\n // extract the attr\n if (Array.isArray(matchingSelector)) {\n const [selector, attr] = matchingSelector;\n result = $(selector).attr(attr).trim();\n } else {\n result = $(matchingSelector).text().trim();\n }\n\n // Allow custom extractor to skip default cleaner\n // for this type; defaults to true\n if (defaultCleaner) {\n return Cleaners[type](result, opts);\n }\n\n return result;\n}\n\nfunction extractResult(opts) {\n const { type, extractor, fallback = true } = opts;\n\n const result = select({ ...opts, extractionOpts: extractor[type] });\n\n // If custom parser succeeds, return the result\n if (result) {\n return result;\n }\n\n // If nothing matches the selector, and fallback is enabled,\n // run the Generic extraction\n if (fallback) return GenericExtractor[type](opts);\n\n return null;\n}\n\nconst RootExtractor = {\n extract(extractor = GenericExtractor, opts) {\n const { contentOnly, extractedTitle } = opts;\n // This is the generic extractor. Run its extract method\n if (extractor.domain === '*') return extractor.extract(opts);\n\n opts = {\n ...opts,\n extractor,\n };\n\n if (contentOnly) {\n const content = extractResult({\n ...opts, type: 'content', extractHtml: true, title: extractedTitle,\n });\n return {\n content,\n };\n }\n const title = extractResult({ ...opts, type: 'title' });\n const date_published = extractResult({ ...opts, type: 'date_published' });\n const author = extractResult({ ...opts, type: 'author' });\n const next_page_url = extractResult({ ...opts, type: 'next_page_url' });\n const content = extractResult({\n ...opts, type: 'content', extractHtml: true, title,\n });\n const lead_image_url = extractResult({ ...opts, type: 'lead_image_url', content });\n const excerpt = extractResult({ ...opts, type: 'excerpt', content });\n const dek = extractResult({ ...opts, type: 'dek', content, excerpt });\n const word_count = extractResult({ ...opts, type: 'word_count', content });\n const direction = extractResult({ ...opts, type: 'direction', title });\n const { url, domain } =\n extractResult({ ...opts, type: 'url_and_domain' }) || { url: null, domain: null };\n\n return {\n title,\n content,\n author,\n date_published,\n lead_image_url,\n dek,\n next_page_url,\n url,\n domain,\n excerpt,\n word_count,\n direction,\n };\n },\n};\n\nexport default RootExtractor;\n","import { removeAnchor } from 'utils/text';\nimport RootExtractor from 'extractors/root-extractor';\nimport GenericExtractor from 'extractors/generic';\nimport Resource from 'resource';\n\nexport default async function collectAllPages(\n {\n next_page_url,\n html,\n $,\n metaCache,\n result,\n Extractor,\n title,\n url,\n }\n) {\n // At this point, we've fetched just the first page\n let pages = 1;\n const previousUrls = [removeAnchor(url)];\n\n // If we've gone over 26 pages, something has\n // likely gone wrong.\n while (next_page_url && pages < 26) {\n pages += 1;\n $ = await Resource.create(next_page_url);\n html = $.html();\n\n const extractorOpts = {\n url: next_page_url,\n html,\n $,\n metaCache,\n contentOnly: true,\n extractedTitle: title,\n previousUrls,\n };\n\n const nextPageResult = RootExtractor.extract(Extractor, extractorOpts);\n\n previousUrls.push(next_page_url);\n result = {\n ...result,\n content: `\n ${result.content}\n <hr>\n <h4>Page ${pages}</h4>\n ${nextPageResult.content}\n `,\n };\n\n next_page_url = nextPageResult.next_page_url;\n }\n\n const word_count = GenericExtractor.word_count({ content: `<div>${result.content}</div>` });\n return {\n ...result,\n total_pages: pages,\n pages_rendered: pages,\n word_count,\n };\n}\n","import URL from 'url';\n\nimport Resource from 'resource';\nimport {\n validateUrl,\n Errors,\n} from 'utils';\nimport getExtractor from 'extractors/get-extractor';\nimport RootExtractor from 'extractors/root-extractor';\nimport collectAllPages from 'extractors/collect-all-pages';\n\nconst Mercury = {\n async parse(url, html, opts = {}) {\n const {\n fetchAllPages = true,\n fallback = true,\n } = opts;\n\n const parsedUrl = URL.parse(url);\n\n if (!validateUrl(parsedUrl)) {\n return Errors.badUrl;\n }\n\n const Extractor = getExtractor(url, parsedUrl);\n // console.log(`Using extractor for ${Extractor.domain}`);\n\n const $ = await Resource.create(url, html, parsedUrl);\n\n // If we found an error creating the resource, return that error\n if ($.error) {\n return $;\n }\n\n html = $.html();\n\n // Cached value of every meta name in our document.\n // Used when extracting title/author/date_published/dek\n const metaCache = $('meta').map((_, node) => $(node).attr('name')).toArray();\n\n let result = RootExtractor.extract(Extractor, { url, html, $, metaCache, parsedUrl, fallback });\n const { title, next_page_url } = result;\n\n // Fetch more pages if next_page_url found\n if (fetchAllPages && next_page_url) {\n result = await collectAllPages(\n {\n Extractor,\n next_page_url,\n html,\n $,\n metaCache,\n result,\n title,\n url,\n }\n );\n } else {\n result = {\n ...result,\n total_pages: 1,\n rendered_pages: 1,\n };\n }\n\n return result;\n },\n\n // A convenience method for getting a resource\n // to work with, e.g., for custom extractor generator\n async fetchResource(url) {\n return await Resource.create(url);\n },\n\n};\n\nexport default Mercury;\n"],"names":["range","start","end","validateUrl","hostname","Errors","REQUEST_HEADERS","FETCH_TIMEOUT","BAD_CONTENT_TYPES","BAD_CONTENT_TYPES_RE","RegExp","join","MAX_CONTENT_LENGTH","get","options","resolve","reject","err","response","body","validateResponse","parseNon2xx","statusMessage","statusCode","Error","error","headers","contentType","contentLength","test","url","parsedUrl","URL","parse","encodeURI","badUrl","fetchResource","convertMetaProp","$","from","to","each","_","node","$node","value","attr","removeAttr","normalizeMetaTags","IS_LINK","IS_IMAGE","TAGS_TO_REMOVE","convertLazyLoadedImages","img","attribs","forEach","isComment","index","type","cleanComments","root","find","contents","filter","remove","clean","Resource","preparedResponse","validResponse","result","generateDoc","content","includes","cheerio","load","normalizeWhitespace","children","length","NYMagExtractor","$children","tagName","BloggerExtractor","WikipediaExtractor","$parent","parents","prepend","TwitterExtractor","tweets","$tweetContainer","append","replaceWith","NYTimesExtractor","src","width","replace","TheAtlanticExtractor","NewYorkerExtractor","WiredExtractor","MSNExtractor","YahooExtractor","BuzzfeedExtractor","WikiaExtractor","LittleThingsExtractor","PoliticoExtractor","DeadspinExtractor","youtubeId","split","BroadwayWorldExtractor","ApartmentTherapyExtractor","data","JSON","sources","$img","MediumExtractor","ytRe","thumb","decodeURIComponent","match","clone","Extractors","SPACER_RE","KEEP_CLASS","KEEP_SELECTORS","STRIP_OUTPUT_TAGS","REMOVE_ATTRS","REMOVE_ATTR_SELECTORS","map","selector","REMOVE_ATTR_LIST","WHITELIST_ATTRS","WHITELIST_ATTRS_RE","REMOVE_EMPTY_TAGS","REMOVE_EMPTY_SELECTORS","tag","CLEAN_CONDITIONALLY_TAGS","HEADER_TAGS","HEADER_TAG_LIST","UNLIKELY_CANDIDATES_BLACKLIST","UNLIKELY_CANDIDATES_WHITELIST","DIV_TO_P_BLOCK_TAGS","NON_TOP_CANDIDATE_TAGS","NON_TOP_CANDIDATE_TAGS_RE","PHOTO_HINTS","PHOTO_HINTS_RE","POSITIVE_SCORE_HINTS","POSITIVE_SCORE_RE","NEGATIVE_SCORE_HINTS","NEGATIVE_SCORE_RE","IS_WP_SELECTOR","EXTRANEOUS_LINK_HINTS","EXTRANEOUS_LINK_HINTS_RE","PAGE_RE","BLOCK_LEVEL_TAGS","BLOCK_LEVEL_TAGS_RE","candidatesBlacklist","CANDIDATES_BLACKLIST","candidatesWhitelist","CANDIDATES_WHITELIST","stripUnlikelyCandidates","not","classes","id","classAndId","brsToPs","collapsing","element","nextElement","next","paragraphize","br","sibling","nextSibling","p","appendTo","convertDivs","div","$div","convertable","convertSpans","span","$span","convertToParagraphs","convertNodeTo","attribString","key","cleanForHeight","height","parseInt","removeSpacers","cleanImages","$article","markToKeep","article","tags","protocol","addClass","stripJunkTags","removeClass","cleanHOnes","$hOnes","removeAllButWhitelist","reduce","acc","cleanAttributes","parent","removeEmpty","$p","text","trim","HNEWS_CONTENT_SELECTORS","READABILITY_ASSET","PARAGRAPH_SCORE_TAGS","CHILD_CONTENT_TAGS","BAD_TAGS","getWeight","score","getScore","parseFloat","scoreCommas","idkRe","scoreLength","textLength","chunks","lengthBonus","Math","min","max","scoreParagraph","slice","setScore","addScore","amount","getOrInitScore","e","addToParent","weightNodes","scoreNode","addScoreTo","scorePs","rawScore","scoreContent","parentSelector","childSelector","NORMALIZE_RE","normalizeSpaces","extractFromUrl","regexList","matchRe","re","exec","PAGE_IN_HREF_RE","HAS_ALPHA_RE","IS_ALPHA_RE","IS_DIGIT_RE","pageNumFromUrl","matches","pageNum","removeAnchor","isGoodSegment","segment","firstSegmentHasLetters","goodSegment","toLowerCase","articleBaseUrl","parsed","host","path","cleanedSegments","reverse","rawSegment","possibleSegment","fileExt","push","SENTENCE_END_RE","hasSentenceEnd","excerptContent","words","mergeSiblings","$candidate","topScore","siblingScoreThreshold","wrappingDiv","$sibling","siblingScore","contentBonus","density","linkDensity","newScore","siblingContent","siblingContentLength","findTopCandidate","first","removeUnlessContent","weight","hasClass","pCount","inputCount","imgCount","nodeIsList","previousNode","prev","scriptCount","cleanTags","cleanHeaders","title","header","$header","prevAll","rewriteTopLevel","absolutize","rootUrl","$content","absoluteUrl","makeLinksAbsolute","totalTextLength","linkText","linkLength","extractFromMeta","metaNames","cachedNames","foundNames","indexOf","name","nodes","values","toArray","metaValue","stripTags","isGoodNode","maxChildren","withinComment","extractFromSelectors","selectors","textOnly","html","cleanText","commentParent","class","undefined","nodeIsSufficient","isWordpress","CLEAN_AUTHOR_RE","TEXT_LINK_RE","MS_DATE_STRING","SEC_DATE_STRING","CLEAN_DATE_STRING_RE","TIME_MERIDIAN_SPACE_RE","TIME_MERIDIAN_DOTS_RE","months","allMonths","timestamp1","timestamp2","SPLIT_DATE_STRING","TITLE_SPLITTERS_RE","DOMAIN_ENDINGS_RE","cleanAuthor","author","leadImageUrl","validUrl","isWebUri","cleanDek","dek","excerpt","dekText","cleanDateString","dateString","cleanDatePublished","date","moment","Date","isValid","toISOString","extractCleanNode","cleanConditionally","defaultCleaner","cleanTitle","resolveSplitTitle","h1","extractBreadcrumbTitle","splitTitle","termCounts","titleText","maxTerm","termCount","splitEnds","longestEnd","cleanDomainFromTitle","nakedDomain","startSlug","startSlugRatio","wuzzy","levenshtein","endSlug","endSlugRatio","newTitle","Cleaners","cleanImage","cleanContent","extractBestNode","opts","$topCandidate","GenericContentExtractor","defaultOpts","getContentNode","cleanAndReturnNode","k","STRONG_TITLE_META_TAGS","WEAK_TITLE_META_TAGS","STRONG_TITLE_SELECTORS","WEAK_TITLE_SELECTORS","GenericTitleExtractor","metaCache","AUTHOR_META_TAGS","AUTHOR_MAX_LENGTH","AUTHOR_SELECTORS","bylineRe","BYLINE_SELECTORS_RE","GenericAuthorExtractor","regex","DATE_PUBLISHED_META_TAGS","DATE_PUBLISHED_SELECTORS","abbrevMonthsStr","DATE_PUBLISHED_URL_RES","GenericDatePublishedExtractor","datePublished","GenericDekExtractor","LEAD_IMAGE_URL_META_TAGS","LEAD_IMAGE_URL_SELECTORS","POSITIVE_LEAD_IMAGE_URL_HINTS","POSITIVE_LEAD_IMAGE_URL_HINTS_RE","NEGATIVE_LEAD_IMAGE_URL_HINTS","NEGATIVE_LEAD_IMAGE_URL_HINTS_RE","GIF_RE","JPG_RE","getSig","scoreImageUrl","scoreAttr","scoreByParents","$figParent","$gParent","scoreBySibling","scoreByDimensions","area","round","scoreByPosition","$imgs","GenericLeadImageUrlExtractor","cleanUrl","imageUrl","imgs","imgScores","topUrl","href","scoreSimilarity","articleUrl","similarity","difflib","SequenceMatcher","ratio","diffPercent","diffModifier","scoreLinkText","linkTextAsNum","scorePageInLink","isWp","DIGIT_RE","NEXT_LINK_TEXT_RE","CAP_LINK_TEXT_RE","PREV_LINK_TEXT_RE","scoreExtraneousLinks","makeSig","$link","positiveMatch","negativeMatch","parentData","scorePrevLink","linkData","shouldScore","baseUrl","previousUrls","linkHost","fragment","scoreBaseUrl","baseRegex","scoreNextLinkText","scoreCapLinks","makeBaseRegex","scoreLinks","links","scoredPages","possiblePages","link","possiblePage","GenericNextPageUrlExtractor","scoredLinks","topPage","scoredLink","CANONICAL_META_SELECTORS","parseDomain","GenericUrlExtractor","$canonical","metaUrl","EXCERPT_META_SELECTORS","maxLength","ellipsize","ellipse","GenericExcerptExtractor","shortContent","GenericWordCountExtractor","GenericExtractor","extract","bind","stringDirection","getDirection","date_published","lead_image_url","next_page_url","word_count","direction","url_and_domain","domain","getExtractor","baseDomain","cleanBySelectors","transformElements","transforms","$matches","findMatchingSelector","Array","isArray","s","select","extractionOpts","extractHtml","matchingSelector","wrap","extractResult","extractor","fallback","RootExtractor","contentOnly","extractedTitle","Extractor","pages","create","extractorOpts","nextPageResult","collectAllPages","Mercury","fetchAllPages"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":null,"sources":["../src/utils/range.js","../src/utils/validate-url.js","../src/utils/errors.js","../src/resource/utils/constants.js","../src/resource/utils/fetch-resource.js","../src/resource/utils/dom/normalize-meta-tags.js","../src/resource/utils/dom/constants.js","../src/resource/utils/dom/convert-lazy-loaded-images.js","../src/resource/utils/dom/clean.js","../src/resource/index.js","../src/utils/merge-supported-domains.js","../src/extractors/custom/nymag.com/index.js","../src/extractors/custom/blogspot.com/index.js","../src/extractors/custom/wikipedia.org/index.js","../src/extractors/custom/twitter.com/index.js","../src/extractors/custom/www.nytimes.com/index.js","../src/extractors/custom/www.theatlantic.com/index.js","../src/extractors/custom/www.newyorker.com/index.js","../src/extractors/custom/www.wired.com/index.js","../src/extractors/custom/www.msn.com/index.js","../src/extractors/custom/www.yahoo.com/index.js","../src/extractors/custom/www.buzzfeed.com/index.js","../src/extractors/custom/fandom.wikia.com/index.js","../src/extractors/custom/www.littlethings.com/index.js","../src/extractors/custom/www.politico.com/index.js","../src/extractors/custom/deadspin.com/index.js","../src/extractors/custom/www.broadwayworld.com/index.js","../src/extractors/custom/www.apartmenttherapy.com/index.js","../src/extractors/custom/medium.com/index.js","../src/extractors/all.js","../src/utils/dom/constants.js","../src/utils/dom/strip-unlikely-candidates.js","../src/utils/dom/brs-to-ps.js","../src/utils/dom/paragraphize.js","../src/utils/dom/convert-to-paragraphs.js","../src/utils/dom/convert-node-to.js","../src/utils/dom/clean-images.js","../src/utils/dom/mark-to-keep.js","../src/utils/dom/strip-junk-tags.js","../src/utils/dom/clean-h-ones.js","../src/utils/dom/clean-attributes.js","../src/utils/dom/remove-empty.js","../src/extractors/generic/content/scoring/constants.js","../src/extractors/generic/content/scoring/get-weight.js","../src/extractors/generic/content/scoring/get-score.js","../src/extractors/generic/content/scoring/score-commas.js","../src/extractors/generic/content/scoring/score-length.js","../src/extractors/generic/content/scoring/score-paragraph.js","../src/extractors/generic/content/scoring/set-score.js","../src/extractors/generic/content/scoring/add-score.js","../src/extractors/generic/content/scoring/add-to-parent.js","../src/extractors/generic/content/scoring/get-or-init-score.js","../src/extractors/generic/content/scoring/score-node.js","../src/extractors/generic/content/scoring/score-content.js","../src/utils/text/normalize-spaces.js","../src/utils/text/extract-from-url.js","../src/utils/text/constants.js","../src/utils/text/page-num-from-url.js","../src/utils/text/remove-anchor.js","../src/utils/text/article-base-url.js","../src/utils/text/has-sentence-end.js","../src/utils/text/excerpt-content.js","../src/extractors/generic/content/scoring/merge-siblings.js","../src/extractors/generic/content/scoring/find-top-candidate.js","../src/utils/dom/clean-tags.js","../src/utils/dom/clean-headers.js","../src/utils/dom/rewrite-top-level.js","../src/utils/dom/make-links-absolute.js","../src/utils/dom/link-density.js","../src/utils/dom/extract-from-meta.js","../src/utils/dom/extract-from-selectors.js","../src/utils/dom/strip-tags.js","../src/utils/dom/within-comment.js","../src/utils/dom/node-is-sufficient.js","../src/utils/dom/is-wordpress.js","../src/cleaners/constants.js","../src/cleaners/author.js","../src/cleaners/lead-image-url.js","../src/cleaners/dek.js","../src/cleaners/date-published.js","../src/cleaners/content.js","../src/cleaners/title.js","../src/cleaners/resolve-split-title.js","../src/cleaners/index.js","../src/extractors/generic/content/extract-best-node.js","../src/extractors/generic/content/extractor.js","../src/extractors/generic/title/constants.js","../src/extractors/generic/title/extractor.js","../src/extractors/generic/author/constants.js","../src/extractors/generic/author/extractor.js","../src/extractors/generic/date-published/constants.js","../src/extractors/generic/date-published/extractor.js","../src/extractors/generic/dek/extractor.js","../src/extractors/generic/lead-image-url/constants.js","../src/extractors/generic/lead-image-url/score-image.js","../src/extractors/generic/lead-image-url/extractor.js","../src/extractors/generic/next-page-url/scoring/utils/score-similarity.js","../src/extractors/generic/next-page-url/scoring/utils/score-link-text.js","../src/extractors/generic/next-page-url/scoring/utils/score-page-in-link.js","../src/extractors/generic/next-page-url/scoring/constants.js","../src/extractors/generic/next-page-url/scoring/utils/score-extraneous-links.js","../src/extractors/generic/next-page-url/scoring/utils/score-by-parents.js","../src/extractors/generic/next-page-url/scoring/utils/score-prev-link.js","../src/extractors/generic/next-page-url/scoring/utils/should-score.js","../src/extractors/generic/next-page-url/scoring/utils/score-base-url.js","../src/extractors/generic/next-page-url/scoring/utils/score-next-link-text.js","../src/extractors/generic/next-page-url/scoring/utils/score-cap-links.js","../src/extractors/generic/next-page-url/scoring/score-links.js","../src/extractors/generic/next-page-url/extractor.js","../src/extractors/generic/url/constants.js","../src/extractors/generic/url/extractor.js","../src/extractors/generic/excerpt/constants.js","../src/extractors/generic/excerpt/extractor.js","../src/extractors/generic/word-count/extractor.js","../src/extractors/generic/index.js","../src/extractors/get-extractor.js","../src/extractors/root-extractor.js","../src/extractors/collect-all-pages.js","../src/mercury.js"],"sourcesContent":["export default function* range(start = 1, end = 1) {\n while (start <= end) {\n yield start += 1;\n }\n}\n","// extremely simple url validation as a first step\nexport default function validateUrl({ hostname }) {\n // If this isn't a valid url, return an error message\n return !!hostname;\n}\n","const Errors = {\n badUrl: {\n error: true,\n messages: 'The url parameter passed does not look like a valid URL. Please check your data and try again.',\n },\n};\n\nexport default Errors;\n","export const REQUEST_HEADERS = {\n 'User-Agent': 'Readability - http://readability.com/about/',\n};\n\n// The number of milliseconds to attempt to fetch a resource before timing out.\nexport const FETCH_TIMEOUT = 10000;\n\n// Content types that we do not extract content from\nconst BAD_CONTENT_TYPES = [\n 'audio/mpeg',\n 'image/gif',\n 'image/jpeg',\n 'image/jpg',\n];\n\nexport const BAD_CONTENT_TYPES_RE = new RegExp(`^(${BAD_CONTENT_TYPES.join('|')})$`, 'i');\n\n\n// Use this setting as the maximum size an article can be\n// for us to attempt parsing. Defaults to 5 MB.\nexport const MAX_CONTENT_LENGTH = 5242880;\n\n// Turn the global proxy on or off\n// Proxying is not currently enabled in Python source\n// so not implementing logic in port.\nexport const PROXY_DOMAINS = false;\nexport const REQUESTS_PROXIES = {\n http: 'http://38.98.105.139:33333',\n https: 'http://38.98.105.139:33333',\n};\n\nexport const DOMAINS_TO_PROXY = [\n 'nih.gov',\n 'gutenberg.org',\n];\n","import URL from 'url';\nimport request from 'request';\nimport { Errors } from 'utils';\n\nimport {\n REQUEST_HEADERS,\n FETCH_TIMEOUT,\n BAD_CONTENT_TYPES_RE,\n MAX_CONTENT_LENGTH,\n} from './constants';\n\nfunction get(options) {\n return new Promise((resolve, reject) => {\n request(options, (err, response, body) => {\n if (err) {\n reject(err);\n } else {\n resolve({ body, response });\n }\n });\n });\n}\n\n// Evaluate a response to ensure it's something we should be keeping.\n// This does not validate in the sense of a response being 200 level or\n// not. Validation here means that we haven't found reason to bail from\n// further processing of this url.\n\nexport function validateResponse(response, parseNon2xx = false) {\n // Check if we got a valid status code\n if (response.statusMessage !== 'OK') {\n if (!response.statusCode) {\n throw new Error(\n `Unable to fetch content. Original exception was ${response.error}`\n );\n } else if (!parseNon2xx) {\n throw new Error(\n `Resource returned a response status code of ${response.statusCode} and resource was instructed to reject non-2xx level status codes.`\n );\n }\n }\n\n const {\n 'content-type': contentType,\n 'content-length': contentLength,\n } = response.headers;\n\n // Check that the content is not in BAD_CONTENT_TYPES\n if (BAD_CONTENT_TYPES_RE.test(contentType)) {\n throw new Error(\n `Content-type for this resource was ${contentType} and is not allowed.`\n );\n }\n\n // Check that the content length is below maximum\n if (contentLength > MAX_CONTENT_LENGTH) {\n throw new Error(\n `Content for this resource was too large. Maximum content length is ${MAX_CONTENT_LENGTH}.`\n );\n }\n\n return true;\n}\n\n// Grabs the last two pieces of the URL and joins them back together\n// This is to get the 'livejournal.com' from 'erotictrains.livejournal.com'\nexport function baseDomain({ host }) {\n return host.split('.').slice(-2).join('.');\n}\n\n// Set our response attribute to the result of fetching our URL.\n// TODO: This should gracefully handle timeouts and raise the\n// proper exceptions on the many failure cases of HTTP.\n// TODO: Ensure we are not fetching something enormous. Always return\n// unicode content for HTML, with charset conversion.\n\nexport default async function fetchResource(url, parsedUrl) {\n parsedUrl = parsedUrl || URL.parse(encodeURI(url));\n\n const options = {\n url: parsedUrl,\n headers: { ...REQUEST_HEADERS },\n timeout: FETCH_TIMEOUT,\n // Don't set encoding; fixes issues\n // w/gzipped responses\n encoding: null,\n // Accept cookies\n jar: true,\n // Accept and decode gzip\n gzip: true,\n // Follow any redirect\n followAllRedirects: true,\n };\n\n const { response, body } = await get(options);\n\n try {\n validateResponse(response);\n return { body, response };\n } catch (e) {\n return Errors.badUrl;\n }\n}\n","function convertMetaProp($, from, to) {\n $(`meta[${from}]`).each((_, node) => {\n const $node = $(node);\n\n const value = $node.attr(from);\n $node.attr(to, value);\n $node.removeAttr(from);\n });\n\n return $;\n}\n\n// For ease of use in extracting from meta tags,\n// replace the \"content\" attribute on meta tags with the\n// \"value\" attribute.\n//\n// In addition, normalize 'property' attributes to 'name' for ease of\n// querying later. See, e.g., og or twitter meta tags.\n\nexport default function normalizeMetaTags($) {\n $ = convertMetaProp($, 'content', 'value');\n $ = convertMetaProp($, 'property', 'name');\n return $;\n}\n","export const IS_LINK = new RegExp('https?://', 'i');\nexport const IS_IMAGE = new RegExp('.(png|gif|jpe?g)', 'i');\n\nexport const TAGS_TO_REMOVE = [\n 'script',\n 'style',\n 'form',\n].join(',');\n","import {\n IS_LINK,\n IS_IMAGE,\n} from './constants';\n\n// Convert all instances of images with potentially\n// lazy loaded images into normal images.\n// Many sites will have img tags with no source, or an image tag with a src\n// attribute that a is a placeholer. We need to be able to properly fill in\n// the src attribute so the images are no longer lazy loaded.\nexport default function convertLazyLoadedImages($) {\n $('img').each((_, img) => {\n Reflect.ownKeys(img.attribs).forEach((attr) => {\n const value = img.attribs[attr];\n\n if (attr !== 'src' && IS_LINK.test(value) &&\n IS_IMAGE.test(value)) {\n $(img).attr('src', value);\n }\n });\n });\n\n return $;\n}\n","import { TAGS_TO_REMOVE } from './constants';\n\nfunction isComment(index, node) {\n return node.type === 'comment';\n}\n\nfunction cleanComments($) {\n $.root().find('*')\n .contents()\n .filter(isComment)\n .remove();\n\n return $;\n}\n\nexport default function clean($) {\n $(TAGS_TO_REMOVE).remove();\n\n $ = cleanComments($);\n return $;\n}\n","import cheerio from 'cheerio';\n\nimport { fetchResource } from './utils';\nimport {\n normalizeMetaTags,\n convertLazyLoadedImages,\n clean,\n} from './utils/dom';\n\nconst Resource = {\n\n // Create a Resource.\n //\n // :param url: The URL for the document we should retrieve.\n // :param response: If set, use as the response rather than\n // attempting to fetch it ourselves. Expects a\n // string.\n async create(url, preparedResponse, parsedUrl) {\n let result;\n\n if (preparedResponse) {\n const validResponse = {\n statusMessage: 'OK',\n statusCode: 200,\n headers: {\n 'content-type': 'text/html',\n 'content-length': 500,\n },\n };\n\n result = { body: preparedResponse, response: validResponse };\n } else {\n result = await fetchResource(url, parsedUrl);\n }\n\n if (result.error) {\n return result;\n }\n\n return this.generateDoc(result);\n },\n\n generateDoc({ body: content, response }) {\n const { 'content-type': contentType } = response.headers;\n\n // TODO: Implement is_text function from\n // https://github.com/ReadabilityHoldings/readability/blob/8dc89613241d04741ebd42fa9fa7df1b1d746303/readability/utils/text.py#L57\n if (!contentType.includes('html') &&\n !contentType.includes('text')) {\n throw new Error('Content does not appear to be text.');\n }\n\n let $ = cheerio.load(content, { normalizeWhitespace: true });\n\n if ($.root().children().length === 0) {\n throw new Error('No children, likely a bad parse.');\n }\n\n $ = normalizeMetaTags($);\n $ = convertLazyLoadedImages($);\n $ = clean($);\n\n return $;\n },\n};\n\nexport default Resource;\n","const merge = (extractor, domains) => (\n domains.reduce((acc, domain) => {\n acc[domain] = extractor;\n return acc;\n }, {})\n);\n\nexport default function mergeSupportedDomains(extractor) {\n return extractor.supportedDomains ?\n merge(extractor, [extractor.domain, ...extractor.supportedDomains])\n :\n merge(extractor, [extractor.domain]);\n}\n","export const NYMagExtractor = {\n domain: 'nymag.com',\n content: {\n // Order by most likely. Extractor will stop on first occurrence\n selectors: [\n 'div.article-content',\n 'section.body',\n 'article.article',\n ],\n\n // Selectors to remove from the extracted content\n clean: [\n '.ad',\n '.single-related-story',\n ],\n\n // Object of tranformations to make on matched elements\n // Each key is the selector, each value is the tag to\n // transform to.\n // If a function is given, it should return a string\n // to convert to or nothing (in which case it will not perform\n // the transformation.\n transforms: {\n // Convert h1s to h2s\n h1: 'h2',\n\n // Convert lazy-loaded noscript images to figures\n noscript: ($node) => {\n const $children = $node.children();\n if ($children.length === 1 && $children.get(0).tagName === 'img') {\n return 'figure';\n }\n\n return null;\n },\n },\n },\n\n title: {\n selectors: [\n 'h1.lede-feature-title',\n 'h1.headline-primary',\n 'h1',\n ],\n },\n\n author: {\n selectors: [\n '.by-authors',\n '.lede-feature-author',\n ],\n },\n\n dek: {\n selectors: [\n '.lede-feature-teaser',\n ],\n },\n\n date_published: {\n selectors: [\n ['time.article-timestamp[datetime]', 'datetime'],\n 'time.article-timestamp',\n ],\n },\n};\n","export const BloggerExtractor = {\n domain: 'blogspot.com',\n content: {\n // Blogger is insane and does not load its content\n // initially in the page, but it's all there\n // in noscript\n selectors: [\n '.post-content noscript',\n ],\n\n // Selectors to remove from the extracted content\n clean: [\n ],\n\n // Convert the noscript tag to a div\n transforms: {\n noscript: 'div',\n },\n },\n\n author: {\n selectors: [\n '.post-author-name',\n ],\n },\n\n title: {\n selectors: [\n '.post h2.title',\n ],\n },\n\n date_published: {\n selectors: [\n 'span.publishdate',\n ],\n },\n};\n","export const WikipediaExtractor = {\n domain: 'wikipedia.org',\n content: {\n selectors: [\n '#mw-content-text',\n ],\n\n defaultCleaner: false,\n\n // transform top infobox to an image with caption\n transforms: {\n '.infobox img': ($node) => {\n const $parent = $node.parents('.infobox');\n // Only prepend the first image in .infobox\n if ($parent.children('img').length === 0) {\n $parent.prepend($node);\n }\n },\n '.infobox caption': 'figcaption',\n '.infobox': 'figure',\n },\n\n // Selectors to remove from the extracted content\n clean: [\n '.mw-editsection',\n 'figure tr, figure td, figure tbody',\n '#toc',\n '.navbox',\n ],\n\n },\n\n author: 'Wikipedia Contributors',\n\n title: {\n selectors: [\n 'h2.title',\n ],\n },\n\n date_published: {\n selectors: [\n '#footer-info-lastmod',\n ],\n },\n\n};\n","export const TwitterExtractor = {\n domain: 'twitter.com',\n\n content: {\n transforms: {\n // We're transforming essentially the whole page here.\n // Twitter doesn't have nice selectors, so our initial\n // selector grabs the whole page, then we're re-writing\n // it to fit our needs before we clean it up.\n '.permalink[role=main]': ($node, $) => {\n const tweets = $node.find('.tweet');\n const $tweetContainer = $('<div id=\"TWEETS_GO_HERE\"></div>');\n $tweetContainer.append(tweets);\n $node.replaceWith($tweetContainer);\n },\n\n // Twitter wraps @ with s, which\n // renders as a strikethrough\n s: 'span',\n },\n\n selectors: [\n '.permalink[role=main]',\n ],\n\n defaultCleaner: false,\n\n clean: [\n '.stream-item-footer',\n 'button',\n '.tweet-details-fixer',\n ],\n },\n\n author: {\n selectors: [\n '.tweet.permalink-tweet .username',\n ],\n },\n\n date_published: {\n selectors: [\n ['.permalink-tweet ._timestamp[data-time-ms]', 'data-time-ms'],\n // '.tweet.permalink-tweet .metadata',\n ],\n },\n\n};\n","export const NYTimesExtractor = {\n title: {\n selectors: [\n '.g-headline',\n 'h1.headline',\n ],\n },\n\n author: {\n selectors: [\n ['meta[name=\"author\"]', 'value'],\n '.g-byline',\n '.byline',\n ],\n },\n\n content: {\n selectors: [\n 'div.g-blocks',\n 'article#story',\n ],\n\n defaultCleaner: false,\n\n transforms: {\n 'img.g-lazy': ($node) => {\n let src = $node.attr('src');\n // const widths = $node.attr('data-widths')\n // .slice(1)\n // .slice(0, -1)\n // .split(',');\n // if (widths.length) {\n // width = widths.slice(-1);\n // } else {\n // width = '900';\n // }\n const width = 640;\n\n src = src.replace('{{size}}', width);\n $node.attr('src', src);\n },\n },\n\n clean: [\n '.ad',\n 'header#story-header',\n '.story-body-1 .lede.video',\n '.visually-hidden',\n '#newsletter-promo',\n '.promo',\n '.comments-button',\n '.hidden',\n ],\n },\n\n date_published: null,\n\n lead_image_url: null,\n\n dek: null,\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\nexport const TheAtlanticExtractor = {\n domain: 'www.theatlantic.com',\n title: {\n selectors: [\n 'h1.hed',\n ],\n },\n\n author: {\n selectors: [\n 'article#article .article-cover-extra .metadata .byline a',\n ],\n },\n\n content: {\n selectors: [\n '.article-body',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n date_published: null,\n\n lead_image_url: null,\n\n dek: null,\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const NewYorkerExtractor = {\n domain: 'www.newyorker.com',\n title: {\n selectors: [\n 'h1.title',\n ],\n },\n\n author: {\n selectors: [\n '.contributors',\n ],\n },\n\n content: {\n selectors: [\n 'div#articleBody',\n 'div.articleBody',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n date_published: {\n selectors: [\n ['meta[name=\"article:published_time\"]', 'value'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"og:description\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const WiredExtractor = {\n domain: 'www.wired.com',\n title: {\n selectors: [\n 'h1.post-title',\n // enter title selectors\n ],\n },\n\n author: {\n selectors: [\n 'a[rel=\"author\"]',\n // enter author selectors\n ],\n },\n\n content: {\n selectors: [\n 'article.content',\n // enter content selectors\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n '.visually-hidden',\n\n ],\n },\n\n date_published: {\n selectors: [\n ['meta[itemprop=\"datePublished\"]', 'value'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"og:description\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const MSNExtractor = {\n domain: 'www.msn.com',\n title: {\n selectors: [\n 'h1',\n // enter title selectors\n ],\n },\n\n author: {\n selectors: [\n 'span.authorname-txt',\n // enter author selectors\n ],\n },\n\n content: {\n selectors: [\n 'div.richtext',\n // enter content selectors\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n 'span.caption',\n\n ],\n },\n\n date_published: {\n selectors: [\n 'span.time',\n ],\n },\n\n lead_image_url: {\n selectors: [\n\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"description\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const YahooExtractor = {\n domain: 'www.yahoo.com',\n title: {\n selectors: [\n 'header.canvas-header',\n // enter title selectors\n ],\n },\n\n author: {\n selectors: [\n 'span.provider-name',\n // enter author selectors\n ],\n },\n\n content: {\n selectors: [\n // enter content selectors\n '.content-canvas',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n '.figure-caption',\n\n ],\n },\n\n date_published: {\n selectors: [\n ['time.date[datetime]', 'datetime'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"og:description\"]', 'value'],\n // enter dek selectors\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const BuzzfeedExtractor = {\n domain: 'www.buzzfeed.com',\n title: {\n selectors: [\n 'h1[id=\"post-title\"]',\n // enter title selectors\n ],\n },\n\n author: {\n selectors: [\n 'a[data-action=\"user/username\"]', 'byline__author',\n // enter author selectors\n ],\n },\n\n content: {\n selectors: [\n '#buzz_sub_buzz',\n // enter content selectors\n ],\n\n defaultCleaner: false,\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: {\n h2: 'b',\n },\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n '.instapaper_ignore',\n '.suplist_list_hide .buzz_superlist_item .buzz_superlist_number_inline',\n '.share-box',\n ],\n },\n\n date_published: {\n selectors: [\n '.buzz-datetime',\n // enter author selectors\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"description\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const WikiaExtractor = {\n domain: 'fandom.wikia.com',\n title: {\n selectors: [\n 'h1.entry-title',\n // enter title selectors\n ],\n },\n\n author: {\n selectors: [\n '.author vcard', '.fn',\n // enter author selectors\n ],\n },\n\n content: {\n selectors: [\n '.grid-content',\n '.entry-content',\n // enter content selectors\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n date_published: {\n selectors: [\n ['meta[name=\"article:published_time\"]', 'value'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"og:description\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const LittleThingsExtractor = {\n domain: 'www.littlethings.com',\n title: {\n selectors: [\n 'h1.post-title',\n // enter title selectors\n ],\n },\n\n author: {\n selectors: [\n ['meta[name=\"author\"]', 'value'],\n // enter author selectors\n ],\n },\n\n content: {\n selectors: [\n // enter content selectors\n '.mainContentIntro',\n '.content-wrapper',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const PoliticoExtractor = {\n domain: 'www.politico.com',\n title: {\n selectors: [\n // enter title selectors\n ['meta[name=\"og:title\"]', 'value'],\n ],\n },\n\n author: {\n selectors: [\n '.story-main-content .byline .vcard',\n ],\n },\n\n content: {\n selectors: [\n // enter content selectors\n '.story-main-content',\n '.content-group', '.story-core',\n '.story-text',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: [\n ],\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n 'figcaption',\n ],\n },\n\n date_published: {\n selectors: [\n ['.story-main-content .timestamp time[datetime]', 'datetime'],\n\n ],\n },\n\n lead_image_url: {\n selectors: [\n // enter lead_image_url selectors\n ['meta[name=\"og:image\"]', 'value'],\n\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"description\"]', 'value'],\n ],\n },\n\n next_page_url: null,\n\n excerpt: null,\n};\n","export const DeadspinExtractor = {\n domain: 'deadspin.com',\n\n supportedDomains: [\n 'jezebel.com',\n 'lifehacker.com',\n 'kotaku.com',\n 'gizmodo.com',\n 'jalopnik.com',\n 'kinja.com',\n ],\n\n title: {\n selectors: [\n 'h1.headline',\n ],\n },\n\n author: {\n selectors: [\n '.author',\n ],\n },\n\n content: {\n selectors: [\n '.post-content',\n '.entry-content',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: {\n 'iframe.lazyload[data-recommend-id^=\"youtube://\"]': ($node) => {\n const youtubeId = $node.attr('id').split('youtube-')[1];\n $node.attr('src', `https://www.youtube.com/embed/${youtubeId}`);\n },\n },\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n ],\n },\n\n date_published: {\n selectors: [\n ['time.updated[datetime]', 'datetime'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n // enter selectors\n ],\n },\n\n next_page_url: {\n selectors: [\n // enter selectors\n ],\n },\n\n excerpt: {\n selectors: [\n // enter selectors\n ],\n },\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const BroadwayWorldExtractor = {\n domain: 'www.broadwayworld.com',\n title: {\n selectors: [\n 'h1.article-title',\n ],\n },\n\n author: {\n selectors: [\n 'span[itemprop=author]',\n ],\n },\n\n content: {\n selectors: [\n 'div[itemprop=articlebody]',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: {\n },\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n date_published: {\n selectors: [\n ['meta[itemprop=datePublished]', 'value'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=\"og:description\"]', 'value'],\n ],\n },\n\n next_page_url: {\n selectors: [\n // enter selectors\n ],\n },\n\n excerpt: {\n selectors: [\n // enter selectors\n ],\n },\n};\n","// Rename CustomExtractor\n// to fit your publication\n// (e.g., NYTimesExtractor)\nexport const ApartmentTherapyExtractor = {\n domain: 'www.apartmenttherapy.com',\n title: {\n selectors: [\n 'h1.headline',\n ],\n },\n\n author: {\n selectors: [\n '.PostByline__name',\n ],\n },\n\n content: {\n selectors: [\n 'div.post__content',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: {\n 'div[data-render-react-id=\"images/LazyPicture\"]': ($node, $) => {\n const data = JSON.parse($node.attr('data-props'));\n const { src } = data.sources[0];\n const $img = $('<img />').attr('src', src);\n $node.replaceWith($img);\n },\n },\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n date_published: {\n selectors: [\n ['.PostByline__timestamp[datetime]', 'datetime'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n ['meta[name=description]', 'value'],\n ],\n },\n\n next_page_url: {\n selectors: [\n // enter selectors\n ],\n },\n\n excerpt: {\n selectors: [\n // enter selectors\n ],\n },\n};\n","export const MediumExtractor = {\n domain: 'medium.com',\n\n supportedDomains: [\n 'trackchanges.postlight.com',\n ],\n\n title: {\n selectors: [\n 'h1',\n ],\n },\n\n author: {\n selectors: [\n ['meta[name=\"author\"]', 'value'],\n ],\n },\n\n content: {\n selectors: [\n '.section-content',\n ],\n\n // Is there anything in the content you selected that needs transformed\n // before it's consumable content? E.g., unusual lazy loaded images\n transforms: {\n // Re-write lazy-loaded youtube videos\n iframe: ($node) => {\n const ytRe =\n /https:\\/\\/i.embed.ly\\/.+url=https:\\/\\/i\\.ytimg\\.com\\/vi\\/(\\w+)\\//;\n const thumb = decodeURIComponent($node.attr('data-thumbnail'));\n\n if (ytRe.test(thumb)) {\n const [_, youtubeId] = thumb.match(ytRe) // eslint-disable-line\n $node.attr('src', `https://www.youtube.com/embed/${youtubeId}`);\n const $parent = $node.parents('figure');\n $parent.prepend($node.clone());\n $node.remove();\n }\n },\n },\n\n // Is there anything that is in the result that shouldn't be?\n // The clean selectors will remove anything that matches from\n // the result\n clean: [\n\n ],\n },\n\n date_published: {\n selectors: [\n ['time[datetime]', 'datetime'],\n ],\n },\n\n lead_image_url: {\n selectors: [\n ['meta[name=\"og:image\"]', 'value'],\n ],\n },\n\n dek: {\n selectors: [\n // enter selectors\n ],\n },\n\n next_page_url: {\n selectors: [\n // enter selectors\n ],\n },\n\n excerpt: {\n selectors: [\n // enter selectors\n ],\n },\n};\n","import mergeSupportedDomains from 'utils/merge-supported-domains';\nimport { NYMagExtractor } from './custom/nymag.com';\nimport { BloggerExtractor } from './custom/blogspot.com';\nimport { WikipediaExtractor } from './custom/wikipedia.org';\nimport { TwitterExtractor } from './custom/twitter.com';\nimport { NYTimesExtractor } from './custom/www.nytimes.com';\nimport { TheAtlanticExtractor } from './custom/www.theatlantic.com';\nimport { NewYorkerExtractor } from './custom/www.newyorker.com';\nimport { WiredExtractor } from './custom/www.wired.com';\nimport { MSNExtractor } from './custom/www.msn.com';\nimport { YahooExtractor } from './custom/www.yahoo.com';\nimport { BuzzfeedExtractor } from './custom/www.buzzfeed.com';\nimport { WikiaExtractor } from './custom/fandom.wikia.com';\nimport { LittleThingsExtractor } from './custom/www.littlethings.com';\nimport { PoliticoExtractor } from './custom/www.politico.com';\nimport { DeadspinExtractor } from './custom/deadspin.com';\nimport { BroadwayWorldExtractor } from './custom/www.broadwayworld.com';\nimport { ApartmentTherapyExtractor } from './custom/www.apartmenttherapy.com';\nimport { MediumExtractor } from './custom/medium.com';\n\nconst Extractors = {\n 'nymag.com': NYMagExtractor,\n 'blogspot.com': BloggerExtractor,\n 'wikipedia.org': WikipediaExtractor,\n 'twitter.com': TwitterExtractor,\n 'www.nytimes.com': NYTimesExtractor,\n 'www.theatlantic.com': TheAtlanticExtractor,\n 'www.newyorker.com': NewYorkerExtractor,\n 'www.wired.com': WiredExtractor,\n 'www.msn.com': MSNExtractor,\n 'www.yahoo.com': YahooExtractor,\n 'www.buzzfeed.com': BuzzfeedExtractor,\n 'fandom.wikia.com': WikiaExtractor,\n 'www.littlethings.com': LittleThingsExtractor,\n 'www.politico.com': PoliticoExtractor,\n ...mergeSupportedDomains(DeadspinExtractor),\n 'www.broadwayworld.com': BroadwayWorldExtractor,\n 'www.apartmenttherapy.com': ApartmentTherapyExtractor,\n ...mergeSupportedDomains(MediumExtractor),\n};\n\nexport default Extractors;\n","// Spacer images to be removed\nexport const SPACER_RE = new RegExp('trans|transparent|spacer|blank', 'i');\n\n// The class we will use to mark elements we want to keep\n// but would normally remove\nexport const KEEP_CLASS = 'mercury-parser-keep';\n\nexport const KEEP_SELECTORS = [\n 'iframe[src^=\"https://www.youtube.com\"]',\n 'iframe[src^=\"http://www.youtube.com\"]',\n 'iframe[src^=\"https://player.vimeo\"]',\n 'iframe[src^=\"http://player.vimeo\"]',\n];\n\n// A list of tags to strip from the output if we encounter them.\nexport const STRIP_OUTPUT_TAGS = [\n 'title',\n 'script',\n 'noscript',\n 'link',\n 'style',\n 'hr',\n 'embed',\n 'iframe',\n 'object',\n];\n\n// cleanAttributes\nexport const REMOVE_ATTRS = ['style', 'align'];\nexport const REMOVE_ATTR_SELECTORS = REMOVE_ATTRS.map(selector => `[${selector}]`);\nexport const REMOVE_ATTR_LIST = REMOVE_ATTRS.join(',');\nexport const WHITELIST_ATTRS = ['src', 'srcset', 'href', 'class', 'id', 'alt'];\nexport const WHITELIST_ATTRS_RE = new RegExp(`^(${WHITELIST_ATTRS.join('|')})$`, 'i');\n\n// removeEmpty\nexport const REMOVE_EMPTY_TAGS = ['p'];\nexport const REMOVE_EMPTY_SELECTORS = REMOVE_EMPTY_TAGS.map(tag => `${tag}:empty`).join(',');\n\n// cleanTags\nexport const CLEAN_CONDITIONALLY_TAGS = ['ul', 'ol', 'table', 'div', 'button', 'form'].join(',');\n\n// cleanHeaders\nconst HEADER_TAGS = ['h2', 'h3', 'h4', 'h5', 'h6'];\nexport const HEADER_TAG_LIST = HEADER_TAGS.join(',');\n\n\n// // CONTENT FETCHING CONSTANTS ////\n\n// A list of strings that can be considered unlikely candidates when\n// extracting content from a resource. These strings are joined together\n// and then tested for existence using re:test, so may contain simple,\n// non-pipe style regular expression queries if necessary.\nexport const UNLIKELY_CANDIDATES_BLACKLIST = [\n 'ad-break',\n 'adbox',\n 'advert',\n 'addthis',\n 'agegate',\n 'aux',\n 'blogger-labels',\n 'combx',\n 'comment',\n 'conversation',\n 'disqus',\n 'entry-unrelated',\n 'extra',\n 'foot',\n // 'form', // This is too generic, has too many false positives\n 'header',\n 'hidden',\n 'loader',\n 'login', // Note: This can hit 'blogindex'.\n 'menu',\n 'meta',\n 'nav',\n 'outbrain',\n 'pager',\n 'pagination',\n 'predicta', // readwriteweb inline ad box\n 'presence_control_external', // lifehacker.com container full of false positives\n 'popup',\n 'printfriendly',\n 'related',\n 'remove',\n 'remark',\n 'rss',\n 'share',\n 'shoutbox',\n 'sidebar',\n 'sociable',\n 'sponsor',\n 'taboola',\n 'tools',\n];\n\n// A list of strings that can be considered LIKELY candidates when\n// extracting content from a resource. Essentially, the inverse of the\n// blacklist above - if something matches both blacklist and whitelist,\n// it is kept. This is useful, for example, if something has a className\n// of \"rss-content entry-content\". It matched 'rss', so it would normally\n// be removed, however, it's also the entry content, so it should be left\n// alone.\n//\n// These strings are joined together and then tested for existence using\n// re:test, so may contain simple, non-pipe style regular expression queries\n// if necessary.\nexport const UNLIKELY_CANDIDATES_WHITELIST = [\n 'and',\n 'article',\n 'body',\n 'blogindex',\n 'column',\n 'content',\n 'entry-content-asset',\n 'format', // misuse of form\n 'hfeed',\n 'hentry',\n 'hatom',\n 'main',\n 'page',\n 'posts',\n 'shadow',\n];\n\n// A list of tags which, if found inside, should cause a <div /> to NOT\n// be turned into a paragraph tag. Shallow div tags without these elements\n// should be turned into <p /> tags.\nexport const DIV_TO_P_BLOCK_TAGS = [\n 'a',\n 'blockquote',\n 'dl',\n 'div',\n 'img',\n 'p',\n 'pre',\n 'table',\n].join(',');\n\n// A list of tags that should be ignored when trying to find the top candidate\n// for a document.\nexport const NON_TOP_CANDIDATE_TAGS = [\n 'br',\n 'b',\n 'i',\n 'label',\n 'hr',\n 'area',\n 'base',\n 'basefont',\n 'input',\n 'img',\n 'link',\n 'meta',\n];\n\nexport const NON_TOP_CANDIDATE_TAGS_RE =\n new RegExp(`^(${NON_TOP_CANDIDATE_TAGS.join('|')})$`, 'i');\n\n// A list of selectors that specify, very clearly, either hNews or other\n// very content-specific style content, like Blogger templates.\n// More examples here: http://microformats.org/wiki/blog-post-formats\nexport const HNEWS_CONTENT_SELECTORS = [\n ['.hentry', '.entry-content'],\n ['entry', '.entry-content'],\n ['.entry', '.entry_content'],\n ['.post', '.postbody'],\n ['.post', '.post_body'],\n ['.post', '.post-body'],\n];\n\nexport const PHOTO_HINTS = [\n 'figure',\n 'photo',\n 'image',\n 'caption',\n];\nexport const PHOTO_HINTS_RE = new RegExp(PHOTO_HINTS.join('|'), 'i');\n\n\n// A list of strings that denote a positive scoring for this content as being\n// an article container. Checked against className and id.\n//\n// TODO: Perhaps have these scale based on their odds of being quality?\nexport const POSITIVE_SCORE_HINTS = [\n 'article',\n 'articlecontent',\n 'instapaper_body',\n 'blog',\n 'body',\n 'content',\n 'entry-content-asset',\n 'entry',\n 'hentry',\n 'main',\n 'Normal',\n 'page',\n 'pagination',\n 'permalink',\n 'post',\n 'story',\n 'text',\n '[-_]copy', // usatoday\n '\\\\Bcopy',\n];\n\n// The above list, joined into a matching regular expression\nexport const POSITIVE_SCORE_RE = new RegExp(POSITIVE_SCORE_HINTS.join('|'), 'i');\n\n// Readability publisher-specific guidelines\nexport const READABILITY_ASSET = new RegExp('entry-content-asset', 'i');\n\n// A list of strings that denote a negative scoring for this content as being\n// an article container. Checked against className and id.\n//\n// TODO: Perhaps have these scale based on their odds of being quality?\nexport const NEGATIVE_SCORE_HINTS = [\n 'adbox',\n 'advert',\n 'author',\n 'bio',\n 'bookmark',\n 'bottom',\n 'byline',\n 'clear',\n 'com-',\n 'combx',\n 'comment',\n 'comment\\\\B',\n 'contact',\n 'copy',\n 'credit',\n 'crumb',\n 'date',\n 'deck',\n 'excerpt',\n 'featured', // tnr.com has a featured_content which throws us off\n 'foot',\n 'footer',\n 'footnote',\n 'graf',\n 'head',\n 'info',\n 'infotext', // newscientist.com copyright\n 'instapaper_ignore',\n 'jump',\n 'linebreak',\n 'link',\n 'masthead',\n 'media',\n 'meta',\n 'modal',\n 'outbrain', // slate.com junk\n 'promo',\n 'pr_', // autoblog - press release\n 'related',\n 'respond',\n 'roundcontent', // lifehacker restricted content warning\n 'scroll',\n 'secondary',\n 'share',\n 'shopping',\n 'shoutbox',\n 'side',\n 'sidebar',\n 'sponsor',\n 'stamp',\n 'sub',\n 'summary',\n 'tags',\n 'tools',\n 'widget',\n];\n// The above list, joined into a matching regular expression\nexport const NEGATIVE_SCORE_RE = new RegExp(NEGATIVE_SCORE_HINTS.join('|'), 'i');\n\n// XPath to try to determine if a page is wordpress. Not always successful.\nexport const IS_WP_SELECTOR = 'meta[name=generator][value^=WordPress]';\n\n// Match a digit. Pretty clear.\nexport const DIGIT_RE = new RegExp('[0-9]');\n\n// A list of words that, if found in link text or URLs, likely mean that\n// this link is not a next page link.\nexport const EXTRANEOUS_LINK_HINTS = [\n 'print',\n 'archive',\n 'comment',\n 'discuss',\n 'e-mail',\n 'email',\n 'share',\n 'reply',\n 'all',\n 'login',\n 'sign',\n 'single',\n 'adx',\n 'entry-unrelated',\n];\nexport const EXTRANEOUS_LINK_HINTS_RE = new RegExp(EXTRANEOUS_LINK_HINTS.join('|'), 'i');\n\n// Match any phrase that looks like it could be page, or paging, or pagination\nexport const PAGE_RE = new RegExp('pag(e|ing|inat)', 'i');\n\n// Match any link text/classname/id that looks like it could mean the next\n// page. Things like: next, continue, >, >>, » but not >|, »| as those can\n// mean last page.\n// export const NEXT_LINK_TEXT_RE = new RegExp('(next|weiter|continue|>([^\\|]|$)|»([^\\|]|$))', 'i');\nexport const NEXT_LINK_TEXT_RE = /(next|weiter|continue|>([^\\|]|$)|»([^\\|]|$))/i;\n\n// Match any link text/classname/id that looks like it is an end link: things\n// like \"first\", \"last\", \"end\", etc.\nexport const CAP_LINK_TEXT_RE = new RegExp('(first|last|end)', 'i');\n\n// Match any link text/classname/id that looks like it means the previous\n// page.\nexport const PREV_LINK_TEXT_RE = new RegExp('(prev|earl|old|new|<|«)', 'i');\n\n// Match 2 or more consecutive <br> tags\nexport const BR_TAGS_RE = new RegExp('(<br[^>]*>[ \\n\\r\\t]*){2,}', 'i');\n\n// Match 1 BR tag.\nexport const BR_TAG_RE = new RegExp('<br[^>]*>', 'i');\n\n// A list of all of the block level tags known in HTML5 and below. Taken from\n// http://bit.ly/qneNIT\nexport const BLOCK_LEVEL_TAGS = [\n 'article',\n 'aside',\n 'blockquote',\n 'body',\n 'br',\n 'button',\n 'canvas',\n 'caption',\n 'col',\n 'colgroup',\n 'dd',\n 'div',\n 'dl',\n 'dt',\n 'embed',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hgroup',\n 'hr',\n 'li',\n 'map',\n 'object',\n 'ol',\n 'output',\n 'p',\n 'pre',\n 'progress',\n 'section',\n 'table',\n 'tbody',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'tr',\n 'ul',\n 'video',\n];\nexport const BLOCK_LEVEL_TAGS_RE = new RegExp(`^(${BLOCK_LEVEL_TAGS.join('|')})$`, 'i');\n\n\n// The removal is implemented as a blacklist and whitelist, this test finds\n// blacklisted elements that aren't whitelisted. We do this all in one\n// expression-both because it's only one pass, and because this skips the\n// serialization for whitelisted nodes.\nconst candidatesBlacklist = UNLIKELY_CANDIDATES_BLACKLIST.join('|');\nexport const CANDIDATES_BLACKLIST = new RegExp(candidatesBlacklist, 'i');\n\nconst candidatesWhitelist = UNLIKELY_CANDIDATES_WHITELIST.join('|');\nexport const CANDIDATES_WHITELIST = new RegExp(candidatesWhitelist, 'i');\n\nexport const UNLIKELY_RE = new RegExp(`!(${candidatesWhitelist})|(${candidatesBlacklist})`, 'i');\n\n\nexport const PARAGRAPH_SCORE_TAGS = new RegExp('^(p|li|span|pre)$', 'i');\nexport const CHILD_CONTENT_TAGS = new RegExp('^(td|blockquote|ol|ul|dl)$', 'i');\nexport const BAD_TAGS = new RegExp('^(address|form)$', 'i');\n\nexport const HTML_OR_BODY_RE = new RegExp('^(html|body)$', 'i');\n","import {\n CANDIDATES_WHITELIST,\n CANDIDATES_BLACKLIST,\n} from './constants';\n\nexport default function stripUnlikelyCandidates($) {\n // Loop through the provided document and remove any non-link nodes\n // that are unlikely candidates for article content.\n //\n // Links are ignored because there are very often links to content\n // that are identified as non-body-content, but may be inside\n // article-like content.\n //\n // :param $: a cheerio object to strip nodes from\n // :return $: the cleaned cheerio object\n $('*').not('a').each((index, node) => {\n const $node = $(node);\n const classes = $node.attr('class');\n const id = $node.attr('id');\n if (!id && !classes) return;\n\n const classAndId = `${classes || ''} ${id || ''}`;\n if (CANDIDATES_WHITELIST.test(classAndId)) {\n return;\n } else if (CANDIDATES_BLACKLIST.test(classAndId)) {\n $node.remove();\n }\n });\n\n return $;\n}\n","import { paragraphize } from './index';\n\n// ## NOTES:\n// Another good candidate for refactoring/optimizing.\n// Very imperative code, I don't love it. - AP\n\n\n// Given cheerio object, convert consecutive <br /> tags into\n// <p /> tags instead.\n//\n// :param $: A cheerio object\n\nexport default function brsToPs($) {\n let collapsing = false;\n $('br').each((index, element) => {\n const nextElement = $(element).next().get(0);\n\n if (nextElement && nextElement.tagName === 'br') {\n collapsing = true;\n $(element).remove();\n } else if (collapsing) {\n collapsing = false;\n // $(element).replaceWith('<p />')\n paragraphize(element, $, true);\n }\n });\n\n return $;\n}\n","import { BLOCK_LEVEL_TAGS_RE } from './constants';\n\n// Given a node, turn it into a P if it is not already a P, and\n// make sure it conforms to the constraints of a P tag (I.E. does\n// not contain any other block tags.)\n//\n// If the node is a <br />, it treats the following inline siblings\n// as if they were its children.\n//\n// :param node: The node to paragraphize; this is a raw node\n// :param $: The cheerio object to handle dom manipulation\n// :param br: Whether or not the passed node is a br\n\nexport default function paragraphize(node, $, br = false) {\n const $node = $(node);\n\n if (br) {\n let sibling = node.nextSibling;\n const p = $('<p></p>');\n\n // while the next node is text or not a block level element\n // append it to a new p node\n while (sibling && !(sibling.tagName && BLOCK_LEVEL_TAGS_RE.test(sibling.tagName))) {\n const nextSibling = sibling.nextSibling;\n $(sibling).appendTo(p);\n sibling = nextSibling;\n }\n\n $node.replaceWith(p);\n $node.remove();\n return $;\n }\n\n return $;\n}\n","import { brsToPs, convertNodeTo } from 'utils/dom';\n\nimport { DIV_TO_P_BLOCK_TAGS } from './constants';\n\nfunction convertDivs($) {\n $('div').each((index, div) => {\n const $div = $(div);\n const convertable = $div.children(DIV_TO_P_BLOCK_TAGS).length === 0;\n\n if (convertable) {\n convertNodeTo($div, $, 'p');\n }\n });\n\n return $;\n}\n\nfunction convertSpans($) {\n $('span').each((index, span) => {\n const $span = $(span);\n const convertable = $span.parents('p, div').length === 0;\n if (convertable) {\n convertNodeTo($span, $, 'p');\n }\n });\n\n return $;\n}\n\n// Loop through the provided doc, and convert any p-like elements to\n// actual paragraph tags.\n//\n// Things fitting this criteria:\n// * Multiple consecutive <br /> tags.\n// * <div /> tags without block level elements inside of them\n// * <span /> tags who are not children of <p /> or <div /> tags.\n//\n// :param $: A cheerio object to search\n// :return cheerio object with new p elements\n// (By-reference mutation, though. Returned just for convenience.)\n\nexport default function convertToParagraphs($) {\n $ = brsToPs($);\n $ = convertDivs($);\n $ = convertSpans($);\n\n return $;\n}\n","export default function convertNodeTo($node, $, tag = 'p') {\n const node = $node.get(0);\n if (!node) {\n return $;\n }\n const { attribs } = $node.get(0);\n const attribString = Reflect.ownKeys(attribs)\n .map(key => `${key}=${attribs[key]}`)\n .join(' ');\n\n $node.replaceWith(`<${tag} ${attribString}>${$node.contents()}</${tag}>`);\n return $;\n}\n","import { SPACER_RE } from './constants';\n\nfunction cleanForHeight($img, $) {\n const height = parseInt($img.attr('height'), 10);\n const width = parseInt($img.attr('width'), 10) || 20;\n\n // Remove images that explicitly have very small heights or\n // widths, because they are most likely shims or icons,\n // which aren't very useful for reading.\n if ((height || 20) < 10 || width < 10) {\n $img.remove();\n } else if (height) {\n // Don't ever specify a height on images, so that we can\n // scale with respect to width without screwing up the\n // aspect ratio.\n $img.removeAttr('height');\n }\n\n return $;\n}\n\n// Cleans out images where the source string matches transparent/spacer/etc\n// TODO This seems very aggressive - AP\nfunction removeSpacers($img, $) {\n if (SPACER_RE.test($img.attr('src'))) {\n $img.remove();\n }\n\n return $;\n}\n\nexport default function cleanImages($article, $) {\n $article.find('img').each((index, img) => {\n const $img = $(img);\n\n cleanForHeight($img, $);\n removeSpacers($img, $);\n });\n\n return $;\n}\n","import URL from 'url';\n\nimport {\n KEEP_SELECTORS,\n KEEP_CLASS,\n} from './constants';\n\nexport default function markToKeep(article, $, url, tags = []) {\n if (tags.length === 0) {\n tags = KEEP_SELECTORS;\n }\n\n if (url) {\n const { protocol, hostname } = URL.parse(url);\n tags = [...tags, `iframe[src^=\"${protocol}//${hostname}\"]`];\n }\n\n $(tags.join(','), article).addClass(KEEP_CLASS);\n\n return $;\n}\n","import {\n STRIP_OUTPUT_TAGS,\n KEEP_CLASS,\n} from './constants';\n\nexport default function stripJunkTags(article, $, tags = []) {\n if (tags.length === 0) {\n tags = STRIP_OUTPUT_TAGS;\n }\n\n // Remove matching elements, but ignore\n // any element with a class of mercury-parser-keep\n $(tags.join(','), article).not(`.${KEEP_CLASS}`).remove();\n\n // Remove the mercury-parser-keep class from result\n $(`.${KEEP_CLASS}`, article).removeClass(KEEP_CLASS);\n\n return $;\n}\n","import { convertNodeTo } from 'utils/dom';\n\n// H1 tags are typically the article title, which should be extracted\n// by the title extractor instead. If there's less than 3 of them (<3),\n// strip them. Otherwise, turn 'em into H2s.\nexport default function cleanHOnes(article, $) {\n const $hOnes = $('h1', article);\n\n if ($hOnes.length < 3) {\n $hOnes.each((index, node) => $(node).remove());\n } else {\n $hOnes.each((index, node) => {\n convertNodeTo($(node), $, 'h2');\n });\n }\n\n return $;\n}\n","import { WHITELIST_ATTRS_RE } from './constants';\n\nfunction removeAllButWhitelist($article) {\n $article.find('*').each((index, node) => {\n node.attribs = Reflect.ownKeys(node.attribs).reduce((acc, attr) => {\n if (WHITELIST_ATTRS_RE.test(attr)) {\n return { ...acc, [attr]: node.attribs[attr] };\n }\n\n return acc;\n }, {});\n });\n\n return $article;\n}\n\n// function removeAttrs(article, $) {\n// REMOVE_ATTRS.forEach((attr) => {\n// $(`[${attr}]`, article).removeAttr(attr);\n// });\n// }\n\n// Remove attributes like style or align\nexport default function cleanAttributes($article) {\n // Grabbing the parent because at this point\n // $article will be wrapped in a div which will\n // have a score set on it.\n return removeAllButWhitelist(\n $article.parent().length ?\n $article.parent() : $article\n );\n}\n","export default function removeEmpty($article, $) {\n $article.find('p').each((index, p) => {\n const $p = $(p);\n if ($p.find('iframe, img').length === 0 && $p.text().trim() === '') $p.remove();\n });\n\n return $;\n}\n","// // CONTENT FETCHING CONSTANTS ////\n\n// A list of strings that can be considered unlikely candidates when\n// extracting content from a resource. These strings are joined together\n// and then tested for existence using re:test, so may contain simple,\n// non-pipe style regular expression queries if necessary.\nexport const UNLIKELY_CANDIDATES_BLACKLIST = [\n 'ad-break',\n 'adbox',\n 'advert',\n 'addthis',\n 'agegate',\n 'aux',\n 'blogger-labels',\n 'combx',\n 'comment',\n 'conversation',\n 'disqus',\n 'entry-unrelated',\n 'extra',\n 'foot',\n 'form',\n 'header',\n 'hidden',\n 'loader',\n 'login', // Note: This can hit 'blogindex'.\n 'menu',\n 'meta',\n 'nav',\n 'pager',\n 'pagination',\n 'predicta', // readwriteweb inline ad box\n 'presence_control_external', // lifehacker.com container full of false positives\n 'popup',\n 'printfriendly',\n 'related',\n 'remove',\n 'remark',\n 'rss',\n 'share',\n 'shoutbox',\n 'sidebar',\n 'sociable',\n 'sponsor',\n 'tools',\n];\n\n// A list of strings that can be considered LIKELY candidates when\n// extracting content from a resource. Essentially, the inverse of the\n// blacklist above - if something matches both blacklist and whitelist,\n// it is kept. This is useful, for example, if something has a className\n// of \"rss-content entry-content\". It matched 'rss', so it would normally\n// be removed, however, it's also the entry content, so it should be left\n// alone.\n//\n// These strings are joined together and then tested for existence using\n// re:test, so may contain simple, non-pipe style regular expression queries\n// if necessary.\nexport const UNLIKELY_CANDIDATES_WHITELIST = [\n 'and',\n 'article',\n 'body',\n 'blogindex',\n 'column',\n 'content',\n 'entry-content-asset',\n 'format', // misuse of form\n 'hfeed',\n 'hentry',\n 'hatom',\n 'main',\n 'page',\n 'posts',\n 'shadow',\n];\n\n// A list of tags which, if found inside, should cause a <div /> to NOT\n// be turned into a paragraph tag. Shallow div tags without these elements\n// should be turned into <p /> tags.\nexport const DIV_TO_P_BLOCK_TAGS = [\n 'a',\n 'blockquote',\n 'dl',\n 'div',\n 'img',\n 'p',\n 'pre',\n 'table',\n].join(',');\n\n// A list of tags that should be ignored when trying to find the top candidate\n// for a document.\nexport const NON_TOP_CANDIDATE_TAGS = [\n 'br',\n 'b',\n 'i',\n 'label',\n 'hr',\n 'area',\n 'base',\n 'basefont',\n 'input',\n 'img',\n 'link',\n 'meta',\n];\n\nexport const NON_TOP_CANDIDATE_TAGS_RE =\n new RegExp(`^(${NON_TOP_CANDIDATE_TAGS.join('|')})$`, 'i');\n\n// A list of selectors that specify, very clearly, either hNews or other\n// very content-specific style content, like Blogger templates.\n// More examples here: http://microformats.org/wiki/blog-post-formats\nexport const HNEWS_CONTENT_SELECTORS = [\n ['.hentry', '.entry-content'],\n ['entry', '.entry-content'],\n ['.entry', '.entry_content'],\n ['.post', '.postbody'],\n ['.post', '.post_body'],\n ['.post', '.post-body'],\n];\n\nexport const PHOTO_HINTS = [\n 'figure',\n 'photo',\n 'image',\n 'caption',\n];\nexport const PHOTO_HINTS_RE = new RegExp(PHOTO_HINTS.join('|'), 'i');\n\n\n// A list of strings that denote a positive scoring for this content as being\n// an article container. Checked against className and id.\n//\n// TODO: Perhaps have these scale based on their odds of being quality?\nexport const POSITIVE_SCORE_HINTS = [\n 'article',\n 'articlecontent',\n 'instapaper_body',\n 'blog',\n 'body',\n 'content',\n 'entry-content-asset',\n 'entry',\n 'hentry',\n 'main',\n 'Normal',\n 'page',\n 'pagination',\n 'permalink',\n 'post',\n 'story',\n 'text',\n '[-_]copy', // usatoday\n '\\\\Bcopy',\n];\n\n// The above list, joined into a matching regular expression\nexport const POSITIVE_SCORE_RE = new RegExp(POSITIVE_SCORE_HINTS.join('|'), 'i');\n\n// Readability publisher-specific guidelines\nexport const READABILITY_ASSET = new RegExp('entry-content-asset', 'i');\n\n// A list of strings that denote a negative scoring for this content as being\n// an article container. Checked against className and id.\n//\n// TODO: Perhaps have these scale based on their odds of being quality?\nexport const NEGATIVE_SCORE_HINTS = [\n 'adbox',\n 'advert',\n 'author',\n 'bio',\n 'bookmark',\n 'bottom',\n 'byline',\n 'clear',\n 'com-',\n 'combx',\n 'comment',\n 'comment\\\\B',\n 'contact',\n 'copy',\n 'credit',\n 'crumb',\n 'date',\n 'deck',\n 'excerpt',\n 'featured', // tnr.com has a featured_content which throws us off\n 'foot',\n 'footer',\n 'footnote',\n 'graf',\n 'head',\n 'info',\n 'infotext', // newscientist.com copyright\n 'instapaper_ignore',\n 'jump',\n 'linebreak',\n 'link',\n 'masthead',\n 'media',\n 'meta',\n 'modal',\n 'outbrain', // slate.com junk\n 'promo',\n 'pr_', // autoblog - press release\n 'related',\n 'respond',\n 'roundcontent', // lifehacker restricted content warning\n 'scroll',\n 'secondary',\n 'share',\n 'shopping',\n 'shoutbox',\n 'side',\n 'sidebar',\n 'sponsor',\n 'stamp',\n 'sub',\n 'summary',\n 'tags',\n 'tools',\n 'widget',\n];\n// The above list, joined into a matching regular expression\nexport const NEGATIVE_SCORE_RE = new RegExp(NEGATIVE_SCORE_HINTS.join('|'), 'i');\n\n// Match a digit. Pretty clear.\nexport const DIGIT_RE = new RegExp('[0-9]');\n\n// Match 2 or more consecutive <br> tags\nexport const BR_TAGS_RE = new RegExp('(<br[^>]*>[ \\n\\r\\t]*){2,}', 'i');\n\n// Match 1 BR tag.\nexport const BR_TAG_RE = new RegExp('<br[^>]*>', 'i');\n\n// A list of all of the block level tags known in HTML5 and below. Taken from\n// http://bit.ly/qneNIT\nexport const BLOCK_LEVEL_TAGS = [\n 'article',\n 'aside',\n 'blockquote',\n 'body',\n 'br',\n 'button',\n 'canvas',\n 'caption',\n 'col',\n 'colgroup',\n 'dd',\n 'div',\n 'dl',\n 'dt',\n 'embed',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hgroup',\n 'hr',\n 'li',\n 'map',\n 'object',\n 'ol',\n 'output',\n 'p',\n 'pre',\n 'progress',\n 'section',\n 'table',\n 'tbody',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'tr',\n 'ul',\n 'video',\n];\nexport const BLOCK_LEVEL_TAGS_RE = new RegExp(`^(${BLOCK_LEVEL_TAGS.join('|')})$`, 'i');\n\n\n// The removal is implemented as a blacklist and whitelist, this test finds\n// blacklisted elements that aren't whitelisted. We do this all in one\n// expression-both because it's only one pass, and because this skips the\n// serialization for whitelisted nodes.\nconst candidatesBlacklist = UNLIKELY_CANDIDATES_BLACKLIST.join('|');\nexport const CANDIDATES_BLACKLIST = new RegExp(candidatesBlacklist, 'i');\n\nconst candidatesWhitelist = UNLIKELY_CANDIDATES_WHITELIST.join('|');\nexport const CANDIDATES_WHITELIST = new RegExp(candidatesWhitelist, 'i');\n\nexport const UNLIKELY_RE = new RegExp(`!(${candidatesWhitelist})|(${candidatesBlacklist})`, 'i');\n\n\nexport const PARAGRAPH_SCORE_TAGS = new RegExp('^(p|li|span|pre)$', 'i');\nexport const CHILD_CONTENT_TAGS = new RegExp('^(td|blockquote|ol|ul|dl)$', 'i');\nexport const BAD_TAGS = new RegExp('^(address|form)$', 'i');\n\nexport const HTML_OR_BODY_RE = new RegExp('^(html|body)$', 'i');\n","import {\n NEGATIVE_SCORE_RE,\n POSITIVE_SCORE_RE,\n PHOTO_HINTS_RE,\n READABILITY_ASSET,\n} from './constants';\n\n\n// Get the score of a node based on its className and id.\nexport default function getWeight(node) {\n const classes = node.attr('class');\n const id = node.attr('id');\n let score = 0;\n\n if (id) {\n // if id exists, try to score on both positive and negative\n if (POSITIVE_SCORE_RE.test(id)) {\n score += 25;\n }\n if (NEGATIVE_SCORE_RE.test(id)) {\n score -= 25;\n }\n }\n\n if (classes) {\n if (score === 0) {\n // if classes exist and id did not contribute to score\n // try to score on both positive and negative\n if (POSITIVE_SCORE_RE.test(classes)) {\n score += 25;\n }\n if (NEGATIVE_SCORE_RE.test(classes)) {\n score -= 25;\n }\n }\n\n // even if score has been set by id, add score for\n // possible photo matches\n // \"try to keep photos if we can\"\n if (PHOTO_HINTS_RE.test(classes)) {\n score += 10;\n }\n\n // add 25 if class matches entry-content-asset,\n // a class apparently instructed for use in the\n // Readability publisher guidelines\n // https://www.readability.com/developers/guidelines\n if (READABILITY_ASSET.test(classes)) {\n score += 25;\n }\n }\n\n return score;\n}\n\n","// returns the score of a node based on\n// the node's score attribute\n// returns null if no score set\nexport default function getScore($node) {\n return parseFloat($node.attr('score')) || null;\n}\n","// return 1 for every comma in text\nexport default function scoreCommas(text) {\n return (text.match(/,/g) || []).length;\n}\n\n","const idkRe = new RegExp('^(p|pre)$', 'i');\n\nexport default function scoreLength(textLength, tagName = 'p') {\n const chunks = textLength / 50;\n\n if (chunks > 0) {\n let lengthBonus;\n\n // No idea why p or pre are being tamped down here\n // but just following the source for now\n // Not even sure why tagName is included here,\n // since this is only being called from the context\n // of scoreParagraph\n if (idkRe.test(tagName)) {\n lengthBonus = chunks - 2;\n } else {\n lengthBonus = chunks - 1.25;\n }\n\n return Math.min(Math.max(lengthBonus, 0), 3);\n }\n\n return 0;\n}\n\n","import {\n scoreCommas,\n scoreLength,\n} from './index';\n\n// Score a paragraph using various methods. Things like number of\n// commas, etc. Higher is better.\nexport default function scoreParagraph(node) {\n let score = 1;\n const text = node.text().trim();\n const textLength = text.length;\n\n // If this paragraph is less than 25 characters, don't count it.\n if (textLength < 25) {\n return 0;\n }\n\n // Add points for any commas within this paragraph\n score += scoreCommas(text);\n\n // For every 50 characters in this paragraph, add another point. Up\n // to 3 points.\n score += scoreLength(textLength);\n\n // Articles can end with short paragraphs when people are being clever\n // but they can also end with short paragraphs setting up lists of junk\n // that we strip. This negative tweaks junk setup paragraphs just below\n // the cutoff threshold.\n if (text.slice(-1) === ':') {\n score -= 1;\n }\n\n return score;\n}\n\n","\nexport default function setScore($node, $, score) {\n $node.attr('score', score);\n return $node;\n}\n\n","import {\n getOrInitScore,\n setScore,\n} from './index';\n\nexport default function addScore($node, $, amount) {\n try {\n const score = getOrInitScore($node, $) + amount;\n setScore($node, $, score);\n } catch (e) {\n // Ignoring; error occurs in scoreNode\n }\n\n return $node;\n}\n","import { addScore } from './index';\n\n// Adds 1/4 of a child's score to its parent\nexport default function addToParent(node, $, score) {\n const parent = node.parent();\n if (parent) {\n addScore(parent, $, score * 0.25);\n }\n\n return node;\n}\n","import {\n getScore,\n scoreNode,\n getWeight,\n addToParent,\n} from './index';\n\n// gets and returns the score if it exists\n// if not, initializes a score based on\n// the node's tag type\nexport default function getOrInitScore($node, $, weightNodes = true) {\n let score = getScore($node);\n\n if (score) {\n return score;\n }\n\n score = scoreNode($node);\n\n if (weightNodes) {\n score += getWeight($node);\n }\n\n addToParent($node, $, score);\n\n return score;\n}\n\n","import { scoreParagraph } from './index';\nimport {\n PARAGRAPH_SCORE_TAGS,\n CHILD_CONTENT_TAGS,\n BAD_TAGS,\n} from './constants';\n\n// Score an individual node. Has some smarts for paragraphs, otherwise\n// just scores based on tag.\nexport default function scoreNode($node) {\n const { tagName } = $node.get(0);\n\n // TODO: Consider ordering by most likely.\n // E.g., if divs are a more common tag on a page,\n // Could save doing that regex test on every node – AP\n if (PARAGRAPH_SCORE_TAGS.test(tagName)) {\n return scoreParagraph($node);\n } else if (tagName === 'div') {\n return 5;\n } else if (CHILD_CONTENT_TAGS.test(tagName)) {\n return 3;\n } else if (BAD_TAGS.test(tagName)) {\n return -3;\n } else if (tagName === 'th') {\n return -5;\n }\n\n return 0;\n}\n","import { convertNodeTo } from 'utils/dom';\n\nimport { HNEWS_CONTENT_SELECTORS } from './constants';\nimport {\n scoreNode,\n setScore,\n getOrInitScore,\n addScore,\n} from './index';\n\nfunction convertSpans($node, $) {\n if ($node.get(0)) {\n const { tagName } = $node.get(0);\n\n if (tagName === 'span') {\n // convert spans to divs\n convertNodeTo($node, $, 'div');\n }\n }\n}\n\nfunction addScoreTo($node, $, score) {\n if ($node) {\n convertSpans($node, $);\n addScore($node, $, score);\n }\n}\n\nfunction scorePs($, weightNodes) {\n $('p, pre').not('[score]').each((index, node) => {\n // The raw score for this paragraph, before we add any parent/child\n // scores.\n let $node = $(node);\n $node = setScore($node, $, getOrInitScore($node, $, weightNodes));\n\n const $parent = $node.parent();\n const rawScore = scoreNode($node);\n\n addScoreTo($parent, $, rawScore, weightNodes);\n if ($parent) {\n // Add half of the individual content score to the\n // grandparent\n addScoreTo($parent.parent(), $, rawScore / 2, weightNodes);\n }\n });\n\n return $;\n}\n\n// score content. Parents get the full value of their children's\n// content score, grandparents half\nexport default function scoreContent($, weightNodes = true) {\n // First, look for special hNews based selectors and give them a big\n // boost, if they exist\n HNEWS_CONTENT_SELECTORS.forEach(([parentSelector, childSelector]) => {\n $(`${parentSelector} ${childSelector}`).each((index, node) => {\n addScore($(node).parent(parentSelector), $, 80);\n });\n });\n\n // Doubling this again\n // Previous solution caused a bug\n // in which parents weren't retaining\n // scores. This is not ideal, and\n // should be fixed.\n scorePs($, weightNodes);\n scorePs($, weightNodes);\n\n return $;\n}\n","const NORMALIZE_RE = /\\s{2,}/g;\n\nexport default function normalizeSpaces(text) {\n return text.replace(NORMALIZE_RE, ' ').trim();\n}\n","// Given a node type to search for, and a list of regular expressions,\n// look to see if this extraction can be found in the URL. Expects\n// that each expression in r_list will return group(1) as the proper\n// string to be cleaned.\n// Only used for date_published currently.\nexport default function extractFromUrl(url, regexList) {\n const matchRe = regexList.find(re => re.test(url));\n if (matchRe) {\n return matchRe.exec(url)[1];\n }\n\n return null;\n}\n","// An expression that looks to try to find the page digit within a URL, if\n// it exists.\n// Matches:\n// page=1\n// pg=1\n// p=1\n// paging=12\n// pag=7\n// pagination/1\n// paging/88\n// pa/83\n// p/11\n//\n// Does not match:\n// pg=102\n// page:2\nexport const PAGE_IN_HREF_RE = new RegExp('(page|paging|(p(a|g|ag)?(e|enum|ewanted|ing|ination)))?(=|/)([0-9]{1,3})', 'i');\n\nexport const HAS_ALPHA_RE = /[a-z]/i;\n\nexport const IS_ALPHA_RE = /^[a-z]+$/i;\nexport const IS_DIGIT_RE = /^[0-9]+$/i;\n","import { PAGE_IN_HREF_RE } from './constants';\n\nexport default function pageNumFromUrl(url) {\n const matches = url.match(PAGE_IN_HREF_RE);\n if (!matches) return null;\n\n const pageNum = parseInt(matches[6], 10);\n\n // Return pageNum < 100, otherwise\n // return null\n return pageNum < 100 ? pageNum : null;\n}\n","export default function removeAnchor(url) {\n return url.split('#')[0].replace(/\\/$/, '');\n}\n","import URL from 'url';\nimport {\n HAS_ALPHA_RE,\n IS_ALPHA_RE,\n IS_DIGIT_RE,\n PAGE_IN_HREF_RE,\n} from './constants';\n\nfunction isGoodSegment(segment, index, firstSegmentHasLetters) {\n let goodSegment = true;\n\n // If this is purely a number, and it's the first or second\n // url_segment, it's probably a page number. Remove it.\n if (index < 2 && IS_DIGIT_RE.test(segment) && segment.length < 3) {\n goodSegment = true;\n }\n\n // If this is the first url_segment and it's just \"index\",\n // remove it\n if (index === 0 && segment.toLowerCase() === 'index') {\n goodSegment = false;\n }\n\n // If our first or second url_segment is smaller than 3 characters,\n // and the first url_segment had no alphas, remove it.\n if (index < 2 && segment.length < 3 && !firstSegmentHasLetters) {\n goodSegment = false;\n }\n\n return goodSegment;\n}\n\n// Take a URL, and return the article base of said URL. That is, no\n// pagination data exists in it. Useful for comparing to other links\n// that might have pagination data within them.\nexport default function articleBaseUrl(url, parsed) {\n const parsedUrl = parsed || URL.parse(url);\n const { protocol, host, path } = parsedUrl;\n\n let firstSegmentHasLetters = false;\n const cleanedSegments = path.split('/')\n .reverse()\n .reduce((acc, rawSegment, index) => {\n let segment = rawSegment;\n\n // Split off and save anything that looks like a file type.\n if (segment.includes('.')) {\n const [possibleSegment, fileExt] = segment.split('.');\n if (IS_ALPHA_RE.test(fileExt)) {\n segment = possibleSegment;\n }\n }\n\n // If our first or second segment has anything looking like a page\n // number, remove it.\n if (PAGE_IN_HREF_RE.test(segment) && index < 2) {\n segment = segment.replace(PAGE_IN_HREF_RE, '');\n }\n\n // If we're on the first segment, check to see if we have any\n // characters in it. The first segment is actually the last bit of\n // the URL, and this will be helpful to determine if we're on a URL\n // segment that looks like \"/2/\" for example.\n if (index === 0) {\n firstSegmentHasLetters = HAS_ALPHA_RE.test(segment);\n }\n\n // If it's not marked for deletion, push it to cleaned_segments.\n if (isGoodSegment(segment, index, firstSegmentHasLetters)) {\n acc.push(segment);\n }\n\n return acc;\n }, []);\n\n return `${protocol}//${host}${cleanedSegments.reverse().join('/')}`;\n}\n","// Given a string, return True if it appears to have an ending sentence\n// within it, false otherwise.\nconst SENTENCE_END_RE = new RegExp('.( |$)');\nexport default function hasSentenceEnd(text) {\n return SENTENCE_END_RE.test(text);\n}\n\n","export default function excerptContent(content, words = 10) {\n return content.trim()\n .split(/\\s+/)\n .slice(0, words)\n .join(' ');\n}\n","import {\n textLength,\n linkDensity,\n} from 'utils/dom';\nimport { hasSentenceEnd } from 'utils/text';\n\nimport { NON_TOP_CANDIDATE_TAGS_RE } from './constants';\nimport { getScore } from './index';\n\n// Now that we have a top_candidate, look through the siblings of\n// it to see if any of them are decently scored. If they are, they\n// may be split parts of the content (Like two divs, a preamble and\n// a body.) Example:\n// http://articles.latimes.com/2009/oct/14/business/fi-bigtvs14\nexport default function mergeSiblings($candidate, topScore, $) {\n if (!$candidate.parent().length) {\n return $candidate;\n }\n\n const siblingScoreThreshold = Math.max(10, topScore * 0.25);\n const wrappingDiv = $('<div></div>');\n\n $candidate.parent().children().each((index, sibling) => {\n const $sibling = $(sibling);\n // Ignore tags like BR, HR, etc\n if (NON_TOP_CANDIDATE_TAGS_RE.test(sibling.tagName)) {\n return null;\n }\n\n const siblingScore = getScore($sibling);\n if (siblingScore) {\n if ($sibling === $candidate) {\n wrappingDiv.append($sibling);\n } else {\n let contentBonus = 0;\n const density = linkDensity($sibling);\n\n // If sibling has a very low link density,\n // give it a small bonus\n if (density < 0.05) {\n contentBonus += 20;\n }\n\n // If sibling has a high link density,\n // give it a penalty\n if (density >= 0.5) {\n contentBonus -= 20;\n }\n\n // If sibling node has the same class as\n // candidate, give it a bonus\n if ($sibling.attr('class') === $candidate.attr('class')) {\n contentBonus += topScore * 0.2;\n }\n\n const newScore = siblingScore + contentBonus;\n\n if (newScore >= siblingScoreThreshold) {\n return wrappingDiv.append($sibling);\n } else if (sibling.tagName === 'p') {\n const siblingContent = $sibling.text();\n const siblingContentLength = textLength(siblingContent);\n\n if (siblingContentLength > 80 && density < 0.25) {\n return wrappingDiv.append($sibling);\n } else if (siblingContentLength <= 80 && density === 0 &&\n hasSentenceEnd(siblingContent)) {\n return wrappingDiv.append($sibling);\n }\n }\n }\n }\n\n return null;\n });\n\n return wrappingDiv;\n}\n","import { NON_TOP_CANDIDATE_TAGS_RE } from './constants';\nimport { getScore } from './index';\nimport mergeSiblings from './merge-siblings';\n\n// After we've calculated scores, loop through all of the possible\n// candidate nodes we found and find the one with the highest score.\nexport default function findTopCandidate($) {\n let $candidate;\n let topScore = 0;\n\n $('[score]').each((index, node) => {\n // Ignore tags like BR, HR, etc\n if (NON_TOP_CANDIDATE_TAGS_RE.test(node.tagName)) {\n return;\n }\n\n const $node = $(node);\n const score = getScore($node);\n\n if (score > topScore) {\n topScore = score;\n $candidate = $node;\n }\n });\n\n // If we don't have a candidate, return the body\n // or whatever the first element is\n if (!$candidate) {\n return $('body') || $('*').first();\n }\n\n $candidate = mergeSiblings($candidate, topScore, $);\n\n return $candidate;\n}\n","import {\n getScore,\n setScore,\n getOrInitScore,\n scoreCommas,\n} from 'extractors/generic/content/scoring';\n\nimport { CLEAN_CONDITIONALLY_TAGS } from './constants';\nimport { normalizeSpaces } from '../text';\nimport { linkDensity } from './index';\n\nfunction removeUnlessContent($node, $, weight) {\n // Explicitly save entry-content-asset tags, which are\n // noted as valuable in the Publisher guidelines. For now\n // this works everywhere. We may want to consider making\n // this less of a sure-thing later.\n if ($node.hasClass('entry-content-asset')) {\n return;\n }\n\n const content = normalizeSpaces($node.text());\n\n if (scoreCommas(content) < 10) {\n const pCount = $('p', $node).length;\n const inputCount = $('input', $node).length;\n\n // Looks like a form, too many inputs.\n if (inputCount > (pCount / 3)) {\n $node.remove();\n return;\n }\n\n const contentLength = content.length;\n const imgCount = $('img', $node).length;\n\n // Content is too short, and there are no images, so\n // this is probably junk content.\n if (contentLength < 25 && imgCount === 0) {\n $node.remove();\n return;\n }\n\n const density = linkDensity($node);\n\n // Too high of link density, is probably a menu or\n // something similar.\n // console.log(weight, density, contentLength)\n if (weight < 25 && density > 0.2 && contentLength > 75) {\n $node.remove();\n return;\n }\n\n // Too high of a link density, despite the score being\n // high.\n if (weight >= 25 && density > 0.5) {\n // Don't remove the node if it's a list and the\n // previous sibling starts with a colon though. That\n // means it's probably content.\n const tagName = $node.get(0).tagName;\n const nodeIsList = tagName === 'ol' || tagName === 'ul';\n if (nodeIsList) {\n const previousNode = $node.prev();\n if (previousNode && normalizeSpaces(previousNode.text()).slice(-1) === ':') {\n return;\n }\n }\n\n $node.remove();\n return;\n }\n\n const scriptCount = $('script', $node).length;\n\n // Too many script tags, not enough content.\n if (scriptCount > 0 && contentLength < 150) {\n $node.remove();\n return;\n }\n }\n}\n\n// Given an article, clean it of some superfluous content specified by\n// tags. Things like forms, ads, etc.\n//\n// Tags is an array of tag name's to search through. (like div, form,\n// etc)\n//\n// Return this same doc.\nexport default function cleanTags($article, $) {\n $(CLEAN_CONDITIONALLY_TAGS, $article).each((index, node) => {\n const $node = $(node);\n let weight = getScore($node);\n if (!weight) {\n weight = getOrInitScore($node, $);\n setScore($node, $, weight);\n }\n\n // drop node if its weight is < 0\n if (weight < 0) {\n $node.remove();\n } else {\n // deteremine if node seems like content\n removeUnlessContent($node, $, weight);\n }\n });\n\n return $;\n}\n\n","import { getWeight } from 'extractors/generic/content/scoring';\n\nimport { HEADER_TAG_LIST } from './constants';\nimport { normalizeSpaces } from '../text';\n\nexport default function cleanHeaders($article, $, title = '') {\n $(HEADER_TAG_LIST, $article).each((index, header) => {\n const $header = $(header);\n // Remove any headers that appear before all other p tags in the\n // document. This probably means that it was part of the title, a\n // subtitle or something else extraneous like a datestamp or byline,\n // all of which should be handled by other metadata handling.\n if ($($header, $article).prevAll('p').length === 0) {\n return $header.remove();\n }\n\n // Remove any headers that match the title exactly.\n if (normalizeSpaces($(header).text()) === title) {\n return $header.remove();\n }\n\n // If this header has a negative weight, it's probably junk.\n // Get rid of it.\n if (getWeight($(header)) < 0) {\n return $header.remove();\n }\n\n return $header;\n });\n\n return $;\n}\n","import { convertNodeTo } from 'utils/dom';\n\n// Rewrite the tag name to div if it's a top level node like body or\n// html to avoid later complications with multiple body tags.\nexport default function rewriteTopLevel(article, $) {\n // I'm not using context here because\n // it's problematic when converting the\n // top-level/root node - AP\n $ = convertNodeTo($('html'), $, 'div');\n $ = convertNodeTo($('body'), $, 'div');\n\n return $;\n}\n","import URL from 'url';\n\nfunction absolutize($, rootUrl, attr, $content) {\n $(`[${attr}]`, $content).each((_, node) => {\n const url = node.attribs[attr];\n const absoluteUrl = URL.resolve(rootUrl, url);\n\n node.attribs[attr] = absoluteUrl;\n });\n}\n\nexport default function makeLinksAbsolute($content, $, url) {\n ['href', 'src'].forEach(attr => absolutize($, url, attr, $content));\n\n return $content;\n}\n","\nexport function textLength(text) {\n return text.trim()\n .replace(/\\s+/g, ' ')\n .length;\n}\n\n// Determines what percentage of the text\n// in a node is link text\n// Takes a node, returns a float\nexport function linkDensity($node) {\n const totalTextLength = textLength($node.text());\n\n const linkText = $node.find('a').text();\n const linkLength = textLength(linkText);\n\n if (totalTextLength > 0) {\n return linkLength / totalTextLength;\n } else if (totalTextLength === 0 && linkLength > 0) {\n return 1;\n }\n\n return 0;\n}\n","import { stripTags } from 'utils/dom';\n\n// Given a node type to search for, and a list of meta tag names to\n// search for, find a meta tag associated.\nexport default function extractFromMeta(\n $,\n metaNames,\n cachedNames,\n cleanTags = true\n) {\n const foundNames = metaNames.filter(name => cachedNames.indexOf(name) !== -1);\n\n for (const name of foundNames) {\n const type = 'name';\n const value = 'value';\n\n const nodes = $(`meta[${type}=\"${name}\"]`);\n\n // Get the unique value of every matching node, in case there\n // are two meta tags with the same name and value.\n // Remove empty values.\n const values =\n nodes.map((index, node) => $(node).attr(value))\n .toArray()\n .filter(text => text !== '');\n\n // If we have more than one value for the same name, we have a\n // conflict and can't trust any of them. Skip this name. If we have\n // zero, that means our meta tags had no values. Skip this name\n // also.\n if (values.length === 1) {\n let metaValue;\n // Meta values that contain HTML should be stripped, as they\n // weren't subject to cleaning previously.\n if (cleanTags) {\n metaValue = stripTags(values[0], $);\n } else {\n metaValue = values[0];\n }\n\n return metaValue;\n }\n }\n\n // If nothing is found, return null\n return null;\n}\n","import { withinComment } from 'utils/dom';\n\nfunction isGoodNode($node, maxChildren) {\n // If it has a number of children, it's more likely a container\n // element. Skip it.\n if ($node.children().length > maxChildren) {\n return false;\n }\n // If it looks to be within a comment, skip it.\n if (withinComment($node)) {\n return false;\n }\n\n return true;\n}\n\n// Given a a list of selectors find content that may\n// be extractable from the document. This is for flat\n// meta-information, like author, title, date published, etc.\nexport default function extractFromSelectors(\n $,\n selectors,\n maxChildren = 1,\n textOnly = true\n) {\n for (const selector of selectors) {\n const nodes = $(selector);\n\n // If we didn't get exactly one of this selector, this may be\n // a list of articles or comments. Skip it.\n if (nodes.length === 1) {\n const $node = $(nodes[0]);\n\n if (isGoodNode($node, maxChildren)) {\n let content;\n if (textOnly) {\n content = $node.text();\n } else {\n content = $node.html();\n }\n\n if (content) {\n return content;\n }\n }\n }\n }\n\n return null;\n}\n","// strips all tags from a string of text\nexport default function stripTags(text, $) {\n // Wrapping text in html element prevents errors when text\n // has no html\n const cleanText = $(`<span>${text}</span>`).text();\n return cleanText === '' ? text : cleanText;\n}\n","export default function withinComment($node) {\n const parents = $node.parents().toArray();\n const commentParent = parents.find((parent) => {\n const classAndId = `${parent.attribs.class} ${parent.attribs.id}`;\n return classAndId.includes('comment');\n });\n\n return commentParent !== undefined;\n}\n","// Given a node, determine if it's article-like enough to return\n// param: node (a cheerio node)\n// return: boolean\n\nexport default function nodeIsSufficient($node) {\n return $node.text().trim().length >= 100;\n}\n","import { IS_WP_SELECTOR } from './constants';\n\nexport default function isWordpress($) {\n return $(IS_WP_SELECTOR).length > 0;\n}\n","// CLEAN AUTHOR CONSTANTS\nexport const CLEAN_AUTHOR_RE = /^\\s*(posted |written )?by\\s*:?\\s*(.*)/i;\n // author = re.sub(r'^\\s*(posted |written )?by\\s*:?\\s*(.*)(?i)',\n\n// CLEAN DEK CONSTANTS\nexport const TEXT_LINK_RE = new RegExp('http(s)?://', 'i');\n// An ordered list of meta tag names that denote likely article deks.\n// From most distinct to least distinct.\n//\n// NOTE: There are currently no meta tags that seem to provide the right\n// content consistenty enough. Two options were:\n// - og:description\n// - dc.description\n// However, these tags often have SEO-specific junk in them that's not\n// header-worthy like a dek is. Excerpt material at best.\nexport const DEK_META_TAGS = [\n];\n\n// An ordered list of Selectors to find likely article deks. From\n// most explicit to least explicit.\n//\n// Should be more restrictive than not, as a failed dek can be pretty\n// detrimental to the aesthetics of an article.\nexport const DEK_SELECTORS = [\n '.entry-summary',\n];\n\n// CLEAN DATE PUBLISHED CONSTANTS\nexport const MS_DATE_STRING = /^\\d{13}$/i;\nexport const SEC_DATE_STRING = /^\\d{10}$/i;\nexport const CLEAN_DATE_STRING_RE = /^\\s*published\\s*:?\\s*(.*)/i;\nexport const TIME_MERIDIAN_SPACE_RE = /(.*\\d)(am|pm)(.*)/i;\nexport const TIME_MERIDIAN_DOTS_RE = /\\.m\\./i;\nconst months = [\n 'jan',\n 'feb',\n 'mar',\n 'apr',\n 'may',\n 'jun',\n 'jul',\n 'aug',\n 'sep',\n 'oct',\n 'nov',\n 'dec',\n];\nconst allMonths = months.join('|');\nconst timestamp1 = '[0-9]{1,2}:[0-9]{2,2}( ?[ap].?m.?)?';\nconst timestamp2 = '[0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4}';\nexport const SPLIT_DATE_STRING =\n new RegExp(`(${timestamp1})|(${timestamp2})|([0-9]{1,4})|(${allMonths})`, 'ig');\n\n// CLEAN TITLE CONSTANTS\n// A regular expression that will match separating characters on a\n// title, that usually denote breadcrumbs or something similar.\nexport const TITLE_SPLITTERS_RE = /(: | - | \\| )/g;\n\nexport const DOMAIN_ENDINGS_RE =\n new RegExp('.com$|.net$|.org$|.co.uk$', 'g');\n","import { CLEAN_AUTHOR_RE } from './constants';\n\n// Take an author string (like 'By David Smith ') and clean it to\n// just the name(s): 'David Smith'.\nexport default function cleanAuthor(author) {\n return author.replace(CLEAN_AUTHOR_RE, '$2').trim();\n}\n","import validUrl from 'valid-url';\n\nexport default function clean(leadImageUrl) {\n leadImageUrl = leadImageUrl.trim();\n if (validUrl.isWebUri(leadImageUrl)) {\n return leadImageUrl;\n }\n\n return null;\n}\n","import { stripTags } from 'utils/dom';\nimport { excerptContent } from 'utils/text';\n\nimport { TEXT_LINK_RE } from './constants';\n\n// Take a dek HTML fragment, and return the cleaned version of it.\n// Return None if the dek wasn't good enough.\nexport default function cleanDek(dek, { $, excerpt }) {\n // Sanity check that we didn't get too short or long of a dek.\n if (dek.length > 1000 || dek.length < 5) return null;\n\n // Check that dek isn't the same as excerpt\n if (excerpt && excerptContent(excerpt, 10) === excerptContent(dek, 10)) return null;\n\n const dekText = stripTags(dek, $);\n\n // Plain text links shouldn't exist in the dek. If we have some, it's\n // not a good dek - bail.\n if (TEXT_LINK_RE.test(dekText)) return null;\n\n return dekText.trim();\n}\n","import moment from 'moment';\n// Is there a compelling reason to use moment here?\n// Mostly only being used for the isValid() method,\n// but could just check for 'Invalid Date' string.\n\nimport {\n MS_DATE_STRING,\n SEC_DATE_STRING,\n CLEAN_DATE_STRING_RE,\n SPLIT_DATE_STRING,\n TIME_MERIDIAN_SPACE_RE,\n TIME_MERIDIAN_DOTS_RE,\n} from './constants';\n\nexport function cleanDateString(dateString) {\n return (dateString.match(SPLIT_DATE_STRING) || [])\n .join(' ')\n .replace(TIME_MERIDIAN_DOTS_RE, 'm')\n .replace(TIME_MERIDIAN_SPACE_RE, '$1 $2 $3')\n .replace(CLEAN_DATE_STRING_RE, '$1')\n .trim();\n}\n\n// Take a date published string, and hopefully return a date out of\n// it. Return none if we fail.\nexport default function cleanDatePublished(dateString) {\n // If string is in milliseconds or seconds, convert to int\n if (MS_DATE_STRING.test(dateString) || SEC_DATE_STRING.test(dateString)) {\n dateString = parseInt(dateString, 10);\n }\n\n let date = moment(new Date(dateString));\n\n if (!date.isValid()) {\n dateString = cleanDateString(dateString);\n date = moment(new Date(dateString));\n }\n\n return date.isValid() ? date.toISOString() : null;\n}\n","import {\n cleanAttributes,\n cleanHeaders,\n cleanHOnes,\n cleanImages,\n cleanTags,\n removeEmpty,\n rewriteTopLevel,\n markToKeep,\n stripJunkTags,\n makeLinksAbsolute,\n} from 'utils/dom';\n\n// Clean our article content, returning a new, cleaned node.\nexport default function extractCleanNode(\n article,\n {\n $,\n cleanConditionally = true,\n title = '',\n url = '',\n defaultCleaner = true,\n }\n) {\n // Rewrite the tag name to div if it's a top level node like body or\n // html to avoid later complications with multiple body tags.\n rewriteTopLevel(article, $);\n\n // Drop small images and spacer images\n // Only do this is defaultCleaner is set to true;\n // this can sometimes be too aggressive.\n if (defaultCleaner) cleanImages(article, $);\n\n // Mark elements to keep that would normally be removed.\n // E.g., stripJunkTags will remove iframes, so we're going to mark\n // YouTube/Vimeo videos as elements we want to keep.\n markToKeep(article, $, url);\n\n // Drop certain tags like <title>, etc\n // This is -mostly- for cleanliness, not security.\n stripJunkTags(article, $);\n\n // H1 tags are typically the article title, which should be extracted\n // by the title extractor instead. If there's less than 3 of them (<3),\n // strip them. Otherwise, turn 'em into H2s.\n cleanHOnes(article, $);\n\n // Clean headers\n cleanHeaders(article, $, title);\n\n // Make links absolute\n makeLinksAbsolute(article, $, url);\n\n // We used to clean UL's and OL's here, but it was leading to\n // too many in-article lists being removed. Consider a better\n // way to detect menus particularly and remove them.\n // Also optionally running, since it can be overly aggressive.\n if (defaultCleaner) cleanTags(article, $, cleanConditionally);\n\n // Remove empty paragraph nodes\n removeEmpty(article, $);\n\n // Remove unnecessary attributes\n cleanAttributes(article, $);\n\n return article;\n}\n","import { stripTags } from 'utils/dom';\n\nimport { TITLE_SPLITTERS_RE } from './constants';\nimport { resolveSplitTitle } from './index';\n\nexport default function cleanTitle(title, { url, $ }) {\n // If title has |, :, or - in it, see if\n // we can clean it up.\n if (TITLE_SPLITTERS_RE.test(title)) {\n title = resolveSplitTitle(title, url);\n }\n\n // Final sanity check that we didn't get a crazy title.\n // if (title.length > 150 || title.length < 15) {\n if (title.length > 150) {\n // If we did, return h1 from the document if it exists\n const h1 = $('h1');\n if (h1.length === 1) {\n title = h1.text();\n }\n }\n\n // strip any html tags in the title text\n return stripTags(title, $).trim();\n}\n\n","import URL from 'url';\nimport wuzzy from 'wuzzy';\n\nimport {\n TITLE_SPLITTERS_RE,\n DOMAIN_ENDINGS_RE,\n} from './constants';\n\nfunction extractBreadcrumbTitle(splitTitle, text) {\n // This must be a very breadcrumbed title, like:\n // The Best Gadgets on Earth : Bits : Blogs : NYTimes.com\n // NYTimes - Blogs - Bits - The Best Gadgets on Earth\n if (splitTitle.length >= 6) {\n // Look to see if we can find a breadcrumb splitter that happens\n // more than once. If we can, we'll be able to better pull out\n // the title.\n const termCounts = splitTitle.reduce((acc, titleText) => {\n acc[titleText] = acc[titleText] ? acc[titleText] + 1 : 1;\n return acc;\n }, {});\n\n const [maxTerm, termCount] =\n Reflect.ownKeys(termCounts)\n .reduce((acc, key) => {\n if (acc[1] < termCounts[key]) {\n return [key, termCounts[key]];\n }\n\n return acc;\n }, [0, 0]);\n\n // We found a splitter that was used more than once, so it\n // is probably the breadcrumber. Split our title on that instead.\n // Note: max_term should be <= 4 characters, so that \" >> \"\n // will match, but nothing longer than that.\n if (termCount >= 2 && maxTerm.length <= 4) {\n splitTitle = text.split(maxTerm);\n }\n\n const splitEnds = [splitTitle[0], splitTitle.slice(-1)];\n const longestEnd = splitEnds.reduce((acc, end) => acc.length > end.length ? acc : end, '');\n\n if (longestEnd.length > 10) {\n return longestEnd;\n }\n\n return text;\n }\n\n return null;\n}\n\nfunction cleanDomainFromTitle(splitTitle, url) {\n // Search the ends of the title, looking for bits that fuzzy match\n // the URL too closely. If one is found, discard it and return the\n // rest.\n //\n // Strip out the big TLDs - it just makes the matching a bit more\n // accurate. Not the end of the world if it doesn't strip right.\n const { host } = URL.parse(url);\n const nakedDomain = host.replace(DOMAIN_ENDINGS_RE, '');\n\n const startSlug = splitTitle[0].toLowerCase().replace(' ', '');\n const startSlugRatio = wuzzy.levenshtein(startSlug, nakedDomain);\n\n if (startSlugRatio > 0.4 && startSlug.length > 5) {\n return splitTitle.slice(2).join('');\n }\n\n const endSlug = splitTitle.slice(-1)[0].toLowerCase().replace(' ', '');\n const endSlugRatio = wuzzy.levenshtein(endSlug, nakedDomain);\n\n if (endSlugRatio > 0.4 && endSlug.length >= 5) {\n return splitTitle.slice(0, -2).join('');\n }\n\n return null;\n}\n\n// Given a title with separators in it (colons, dashes, etc),\n// resolve whether any of the segments should be removed.\nexport default function resolveSplitTitle(title, url = '') {\n // Splits while preserving splitters, like:\n // ['The New New York', ' - ', 'The Washington Post']\n const splitTitle = title.split(TITLE_SPLITTERS_RE);\n if (splitTitle.length === 1) {\n return title;\n }\n\n let newTitle = extractBreadcrumbTitle(splitTitle, title);\n if (newTitle) return newTitle;\n\n newTitle = cleanDomainFromTitle(splitTitle, url);\n if (newTitle) return newTitle;\n\n // Fuzzy ratio didn't find anything, so this title is probably legit.\n // Just return it all.\n return title;\n}\n","import cleanAuthor from './author';\nimport cleanImage from './lead-image-url';\nimport cleanDek from './dek';\nimport cleanDatePublished from './date-published';\nimport cleanContent from './content';\nimport cleanTitle from './title';\n\nconst Cleaners = {\n author: cleanAuthor,\n lead_image_url: cleanImage,\n dek: cleanDek,\n date_published: cleanDatePublished,\n content: cleanContent,\n title: cleanTitle,\n};\n\n\nexport default Cleaners;\n\nexport { cleanAuthor };\nexport { cleanImage };\nexport { cleanDek };\nexport { cleanDatePublished };\nexport { cleanContent };\nexport { cleanTitle };\nexport { default as resolveSplitTitle } from './resolve-split-title';\n","import {\n stripUnlikelyCandidates,\n convertToParagraphs,\n} from 'utils/dom';\n\nimport {\n scoreContent,\n findTopCandidate,\n} from './scoring';\n\n// Using a variety of scoring techniques, extract the content most\n// likely to be article text.\n//\n// If strip_unlikely_candidates is True, remove any elements that\n// match certain criteria first. (Like, does this element have a\n// classname of \"comment\")\n//\n// If weight_nodes is True, use classNames and IDs to determine the\n// worthiness of nodes.\n//\n// Returns a cheerio object $\nexport default function extractBestNode($, opts) {\n // clone the node so we can get back to our\n // initial parsed state if needed\n // TODO Do I need this? – AP\n // let $root = $.root().clone()\n\n\n if (opts.stripUnlikelyCandidates) {\n $ = stripUnlikelyCandidates($);\n }\n\n $ = convertToParagraphs($);\n $ = scoreContent($, opts.weightNodes);\n const $topCandidate = findTopCandidate($);\n\n return $topCandidate;\n}\n","import cheerio from 'cheerio';\n\nimport { nodeIsSufficient } from 'utils/dom';\nimport { cleanContent } from 'cleaners';\nimport { normalizeSpaces } from 'utils/text';\n\nimport extractBestNode from './extract-best-node';\n\nconst GenericContentExtractor = {\n defaultOpts: {\n stripUnlikelyCandidates: true,\n weightNodes: true,\n cleanConditionally: true,\n },\n\n // Extract the content for this resource - initially, pass in our\n // most restrictive opts which will return the highest quality\n // content. On each failure, retry with slightly more lax opts.\n //\n // :param return_type: string. If \"node\", should return the content\n // as a cheerio node rather than as an HTML string.\n //\n // Opts:\n // stripUnlikelyCandidates: Remove any elements that match\n // non-article-like criteria first.(Like, does this element\n // have a classname of \"comment\")\n //\n // weightNodes: Modify an elements score based on whether it has\n // certain classNames or IDs. Examples: Subtract if a node has\n // a className of 'comment', Add if a node has an ID of\n // 'entry-content'.\n //\n // cleanConditionally: Clean the node to return of some\n // superfluous content. Things like forms, ads, etc.\n extract({ $, html, title, url }, opts) {\n opts = { ...this.defaultOpts, ...opts };\n\n $ = $ || cheerio.load(html);\n\n // Cascade through our extraction-specific opts in an ordered fashion,\n // turning them off as we try to extract content.\n let node = this.getContentNode($, title, url, opts);\n\n if (nodeIsSufficient(node)) {\n return this.cleanAndReturnNode(node, $);\n }\n\n // We didn't succeed on first pass, one by one disable our\n // extraction opts and try again.\n for (const key of Reflect.ownKeys(opts).filter(k => opts[k] === true)) {\n opts[key] = false;\n $ = cheerio.load(html);\n\n node = this.getContentNode($, title, url, opts);\n\n if (nodeIsSufficient(node)) {\n break;\n }\n }\n\n return this.cleanAndReturnNode(node, $);\n },\n\n // Get node given current options\n getContentNode($, title, url, opts) {\n return cleanContent(\n extractBestNode($, opts),\n {\n $,\n cleanConditionally: opts.cleanConditionally,\n title,\n url,\n });\n },\n\n // Once we got here, either we're at our last-resort node, or\n // we broke early. Make sure we at least have -something- before we\n // move forward.\n cleanAndReturnNode(node, $) {\n if (!node) {\n return null;\n }\n\n return normalizeSpaces($.html(node));\n\n // if return_type == \"html\":\n // return normalize_spaces(node_to_html(node))\n // else:\n // return node\n },\n\n};\n\nexport default GenericContentExtractor;\n","// TODO: It would be great if we could merge the meta and selector lists into\n// a list of objects, because we could then rank them better. For example,\n// .hentry .entry-title is far better suited than <meta title>.\n\n// An ordered list of meta tag names that denote likely article titles. All\n// attributes should be lowercase for faster case-insensitive matching. From\n// most distinct to least distinct.\nexport const STRONG_TITLE_META_TAGS = [\n 'tweetmeme-title',\n 'dc.title',\n 'rbtitle',\n 'headline',\n 'title',\n];\n\n// og:title is weak because it typically contains context that we don't like,\n// for example the source site's name. Gotta get that brand into facebook!\nexport const WEAK_TITLE_META_TAGS = [\n 'og:title',\n];\n\n// An ordered list of XPath Selectors to find likely article titles. From\n// most explicit to least explicit.\n//\n// Note - this does not use classes like CSS. This checks to see if the string\n// exists in the className, which is not as accurate as .className (which\n// splits on spaces/endlines), but for our purposes it's close enough. The\n// speed tradeoff is worth the accuracy hit.\nexport const STRONG_TITLE_SELECTORS = [\n '.hentry .entry-title',\n 'h1#articleHeader',\n 'h1.articleHeader',\n 'h1.article',\n '.instapaper_title',\n '#meebo-title',\n];\n\nexport const WEAK_TITLE_SELECTORS = [\n 'article h1',\n '#entry-title',\n '.entry-title',\n '#entryTitle',\n '#entrytitle',\n '.entryTitle',\n '.entrytitle',\n '#articleTitle',\n '.articleTitle',\n 'post post-title',\n 'h1.title',\n 'h2.article',\n 'h1',\n 'html head title',\n 'title',\n];\n","import { cleanTitle } from 'cleaners';\nimport {\n extractFromMeta,\n extractFromSelectors,\n} from 'utils/dom';\n\nimport {\n STRONG_TITLE_META_TAGS,\n WEAK_TITLE_META_TAGS,\n STRONG_TITLE_SELECTORS,\n WEAK_TITLE_SELECTORS,\n} from './constants';\n\nconst GenericTitleExtractor = {\n extract({ $, url, metaCache }) {\n // First, check to see if we have a matching meta tag that we can make\n // use of that is strongly associated with the headline.\n let title;\n\n title = extractFromMeta($, STRONG_TITLE_META_TAGS, metaCache);\n if (title) return cleanTitle(title, { url, $ });\n\n // Second, look through our content selectors for the most likely\n // article title that is strongly associated with the headline.\n title = extractFromSelectors($, STRONG_TITLE_SELECTORS);\n if (title) return cleanTitle(title, { url, $ });\n\n // Third, check for weaker meta tags that may match.\n title = extractFromMeta($, WEAK_TITLE_META_TAGS, metaCache);\n if (title) return cleanTitle(title, { url, $ });\n\n // Last, look for weaker selector tags that may match.\n title = extractFromSelectors($, WEAK_TITLE_SELECTORS);\n if (title) return cleanTitle(title, { url, $ });\n\n // If no matches, return an empty string\n return '';\n },\n};\n\nexport default GenericTitleExtractor;\n","// An ordered list of meta tag names that denote likely article authors. All\n// attributes should be lowercase for faster case-insensitive matching. From\n// most distinct to least distinct.\n//\n// Note: \"author\" is too often the -developer- of the page, so it is not\n// added here.\nexport const AUTHOR_META_TAGS = [\n 'byl',\n 'clmst',\n 'dc.author',\n 'dcsext.author',\n 'dc.creator',\n 'rbauthors',\n 'authors',\n];\n\nexport const AUTHOR_MAX_LENGTH = 300;\n\n// An ordered list of XPath Selectors to find likely article authors. From\n// most explicit to least explicit.\n//\n// Note - this does not use classes like CSS. This checks to see if the string\n// exists in the className, which is not as accurate as .className (which\n// splits on spaces/endlines), but for our purposes it's close enough. The\n// speed tradeoff is worth the accuracy hit.\nexport const AUTHOR_SELECTORS = [\n '.entry .entry-author',\n '.author.vcard .fn',\n '.author .vcard .fn',\n '.byline.vcard .fn',\n '.byline .vcard .fn',\n '.byline .by .author',\n '.byline .by',\n '.byline .author',\n '.post-author.vcard',\n '.post-author .vcard',\n 'a[rel=author]',\n '#by_author',\n '.by_author',\n '#entryAuthor',\n '.entryAuthor',\n '.byline a[href*=author]',\n '#author .authorname',\n '.author .authorname',\n '#author',\n '.author',\n '.articleauthor',\n '.ArticleAuthor',\n '.byline',\n];\n\n// An ordered list of Selectors to find likely article authors, with\n// regular expression for content.\nconst bylineRe = /^[\\n\\s]*By/i;\nexport const BYLINE_SELECTORS_RE = [\n ['#byline', bylineRe],\n ['.byline', bylineRe],\n];\n","import { cleanAuthor } from 'cleaners';\nimport {\n extractFromMeta,\n extractFromSelectors,\n} from 'utils/dom';\n\nimport {\n AUTHOR_META_TAGS,\n AUTHOR_MAX_LENGTH,\n AUTHOR_SELECTORS,\n BYLINE_SELECTORS_RE,\n} from './constants';\n\nconst GenericAuthorExtractor = {\n extract({ $, metaCache }) {\n let author;\n\n // First, check to see if we have a matching\n // meta tag that we can make use of.\n author = extractFromMeta($, AUTHOR_META_TAGS, metaCache);\n if (author && author.length < AUTHOR_MAX_LENGTH) {\n return cleanAuthor(author);\n }\n\n // Second, look through our selectors looking for potential authors.\n author = extractFromSelectors($, AUTHOR_SELECTORS, 2);\n if (author && author.length < AUTHOR_MAX_LENGTH) {\n return cleanAuthor(author);\n }\n\n // Last, use our looser regular-expression based selectors for\n // potential authors.\n for (const [selector, regex] of BYLINE_SELECTORS_RE) {\n const node = $(selector);\n if (node.length === 1) {\n const text = node.text();\n if (regex.test(text)) {\n return cleanAuthor(text);\n }\n }\n }\n\n return null;\n },\n};\n\nexport default GenericAuthorExtractor;\n\n","// An ordered list of meta tag names that denote\n// likely date published dates. All attributes\n// should be lowercase for faster case-insensitive matching.\n// From most distinct to least distinct.\nexport const DATE_PUBLISHED_META_TAGS = [\n 'article:published_time',\n 'displaydate',\n 'dc.date',\n 'dc.date.issued',\n 'rbpubdate',\n 'publish_date',\n 'pub_date',\n 'pagedate',\n 'pubdate',\n 'revision_date',\n 'doc_date',\n 'date_created',\n 'content_create_date',\n 'lastmodified',\n 'created',\n 'date',\n];\n\n// An ordered list of XPath Selectors to find\n// likely date published dates. From most explicit\n// to least explicit.\nexport const DATE_PUBLISHED_SELECTORS = [\n '.hentry .dtstamp.published',\n '.hentry .published',\n '.hentry .dtstamp.updated',\n '.hentry .updated',\n '.single .published',\n '.meta .published',\n '.meta .postDate',\n '.entry-date',\n '.byline .date',\n '.postmetadata .date',\n '.article_datetime',\n '.date-header',\n '.story-date',\n '.dateStamp',\n '#story .datetime',\n '.dateline',\n '.pubdate',\n];\n\n// An ordered list of compiled regular expressions to find likely date\n// published dates from the URL. These should always have the first\n// reference be a date string that is parseable by dateutil.parser.parse\nconst abbrevMonthsStr = '(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)';\nexport const DATE_PUBLISHED_URL_RES = [\n // /2012/01/27/ but not /2012/01/293\n new RegExp('/(20\\\\d{2}/\\\\d{2}/\\\\d{2})/', 'i'),\n // 20120127 or 20120127T but not 2012012733 or 8201201733\n // /[^0-9](20\\d{2}[01]\\d[0-3]\\d)([^0-9]|$)/i,\n // 2012-01-27\n new RegExp('(20\\\\d{2}-[01]\\\\d-[0-3]\\\\d)', 'i'),\n // /2012/jan/27/\n new RegExp(`/(20\\\\d{2}/${abbrevMonthsStr}/[0-3]\\\\d)/`, 'i'),\n];\n\n","import { cleanDatePublished } from 'cleaners';\nimport {\n extractFromMeta,\n extractFromSelectors,\n} from 'utils/dom';\nimport { extractFromUrl } from 'utils/text';\n\nimport {\n DATE_PUBLISHED_META_TAGS,\n DATE_PUBLISHED_SELECTORS,\n DATE_PUBLISHED_URL_RES,\n} from './constants';\n\nconst GenericDatePublishedExtractor = {\n extract({ $, url, metaCache }) {\n let datePublished;\n // First, check to see if we have a matching meta tag\n // that we can make use of.\n // Don't try cleaning tags from this string\n datePublished = extractFromMeta($, DATE_PUBLISHED_META_TAGS, metaCache, false);\n if (datePublished) return cleanDatePublished(datePublished);\n\n // Second, look through our selectors looking for potential\n // date_published's.\n datePublished = extractFromSelectors($, DATE_PUBLISHED_SELECTORS);\n if (datePublished) return cleanDatePublished(datePublished);\n\n // Lastly, look to see if a dately string exists in the URL\n datePublished = extractFromUrl(url, DATE_PUBLISHED_URL_RES);\n if (datePublished) return cleanDatePublished(datePublished);\n\n return null;\n },\n};\n\nexport default GenericDatePublishedExtractor;\n","// import {\n// DEK_META_TAGS,\n// DEK_SELECTORS,\n// DEK_URL_RES,\n// } from './constants';\n\n// import { cleanDek } from 'cleaners';\n\n// import {\n// extractFromMeta,\n// extractFromSelectors,\n// } from 'utils/dom';\n\n// Currently there is only one selector for\n// deks. We should simply return null here\n// until we have a more robust generic option.\n// Below is the original source for this, for reference.\nconst GenericDekExtractor = {\n // extract({ $, content, metaCache }) {\n extract() {\n return null;\n },\n};\n\nexport default GenericDekExtractor;\n\n// def extract_dek(self):\n// # First, check to see if we have a matching meta tag that we can make\n// # use of.\n// dek = self.extract_from_meta('dek', constants.DEK_META_TAGS)\n// if not dek:\n// # Second, look through our CSS/XPath selectors. This may return\n// # an HTML fragment.\n// dek = self.extract_from_selectors('dek',\n// constants.DEK_SELECTORS,\n// text_only=False)\n//\n// if dek:\n// # Make sure our dek isn't in the first few thousand characters\n// # of the content, otherwise it's just the start of the article\n// # and not a true dek.\n// content = self.extract_content()\n// content_chunk = normalize_spaces(strip_tags(content[:2000]))\n// dek_chunk = normalize_spaces(dek[:100]) # Already has no tags.\n//\n// # 80% or greater similarity means the dek was very similar to some\n// # of the starting content, so we skip it.\n// if fuzz.partial_ratio(content_chunk, dek_chunk) < 80:\n// return dek\n//\n// return None\n","// An ordered list of meta tag names that denote likely article leading images.\n// All attributes should be lowercase for faster case-insensitive matching.\n// From most distinct to least distinct.\nexport const LEAD_IMAGE_URL_META_TAGS = [\n 'og:image',\n 'twitter:image',\n 'image_src',\n];\n\nexport const LEAD_IMAGE_URL_SELECTORS = [\n 'link[rel=image_src]',\n];\n\nexport const POSITIVE_LEAD_IMAGE_URL_HINTS = [\n 'upload',\n 'wp-content',\n 'large',\n 'photo',\n 'wp-image',\n];\nexport const POSITIVE_LEAD_IMAGE_URL_HINTS_RE = new RegExp(POSITIVE_LEAD_IMAGE_URL_HINTS.join('|'), 'i');\n\nexport const NEGATIVE_LEAD_IMAGE_URL_HINTS = [\n 'spacer',\n 'sprite',\n 'blank',\n 'throbber',\n 'gradient',\n 'tile',\n 'bg',\n 'background',\n 'icon',\n 'social',\n 'header',\n 'hdr',\n 'advert',\n 'spinner',\n 'loader',\n 'loading',\n 'default',\n 'rating',\n 'share',\n 'facebook',\n 'twitter',\n 'theme',\n 'promo',\n 'ads',\n 'wp-includes',\n];\nexport const NEGATIVE_LEAD_IMAGE_URL_HINTS_RE = new RegExp(NEGATIVE_LEAD_IMAGE_URL_HINTS.join('|'), 'i');\n\nexport const GIF_RE = /\\.gif(\\?.*)?$/i;\nexport const JPG_RE = /\\.jpe?g(\\?.*)?$/i;\n","import {\n POSITIVE_LEAD_IMAGE_URL_HINTS_RE,\n NEGATIVE_LEAD_IMAGE_URL_HINTS_RE,\n GIF_RE,\n JPG_RE,\n} from './constants';\n\nimport { PHOTO_HINTS_RE } from '../content/scoring/constants';\n\nfunction getSig($node) {\n return `${$node.attr('class') || ''} ${$node.attr('id') || ''}`;\n}\n\n// Scores image urls based on a variety of heuristics.\nexport function scoreImageUrl(url) {\n url = url.trim();\n let score = 0;\n\n if (POSITIVE_LEAD_IMAGE_URL_HINTS_RE.test(url)) {\n score += 20;\n }\n\n if (NEGATIVE_LEAD_IMAGE_URL_HINTS_RE.test(url)) {\n score -= 20;\n }\n\n // TODO: We might want to consider removing this as\n // gifs are much more common/popular than they once were\n if (GIF_RE.test(url)) {\n score -= 10;\n }\n\n if (JPG_RE.test(url)) {\n score += 10;\n }\n\n // PNGs are neutral.\n\n return score;\n}\n\n// Alt attribute usually means non-presentational image.\nexport function scoreAttr($img) {\n if ($img.attr('alt')) {\n return 5;\n }\n\n return 0;\n}\n\n// Look through our parent and grandparent for figure-like\n// container elements, give a bonus if we find them\nexport function scoreByParents($img) {\n let score = 0;\n const $figParent = $img.parents('figure').first();\n\n if ($figParent.length === 1) {\n score += 25;\n }\n\n const $parent = $img.parent();\n let $gParent;\n if ($parent.length === 1) {\n $gParent = $parent.parent();\n }\n\n [$parent, $gParent].forEach(($node) => {\n if (PHOTO_HINTS_RE.test(getSig($node))) {\n score += 15;\n }\n });\n\n return score;\n}\n\n// Look at our immediate sibling and see if it looks like it's a\n// caption. Bonus if so.\nexport function scoreBySibling($img) {\n let score = 0;\n const $sibling = $img.next();\n const sibling = $sibling.get(0);\n\n if (sibling && sibling.tagName === 'figcaption') {\n score += 25;\n }\n\n if (PHOTO_HINTS_RE.test(getSig($sibling))) {\n score += 15;\n }\n\n return score;\n}\n\nexport function scoreByDimensions($img) {\n let score = 0;\n\n const width = parseFloat($img.attr('width'));\n const height = parseFloat($img.attr('height'));\n const src = $img.attr('src');\n\n // Penalty for skinny images\n if (width && width <= 50) {\n score -= 50;\n }\n\n // Penalty for short images\n if (height && height <= 50) {\n score -= 50;\n }\n\n if (width && height && !src.includes('sprite')) {\n const area = width * height;\n if (area < 5000) { // Smaller than 50 x 100\n score -= 100;\n } else {\n score += Math.round(area / 1000);\n }\n }\n\n return score;\n}\n\nexport function scoreByPosition($imgs, index) {\n return ($imgs.length / 2) - index;\n}\n","import { extractFromMeta } from 'utils/dom';\nimport { cleanImage } from 'cleaners';\n\nimport {\n LEAD_IMAGE_URL_META_TAGS,\n LEAD_IMAGE_URL_SELECTORS,\n} from './constants';\n\nimport {\n scoreImageUrl,\n scoreAttr,\n scoreByParents,\n scoreBySibling,\n scoreByDimensions,\n scoreByPosition,\n} from './score-image';\n\n// Given a resource, try to find the lead image URL from within\n// it. Like content and next page extraction, uses a scoring system\n// to determine what the most likely image may be. Short circuits\n// on really probable things like og:image meta tags.\n//\n// Potential signals to still take advantage of:\n// * domain\n// * weird aspect ratio\nconst GenericLeadImageUrlExtractor = {\n extract({ $, content, metaCache }) {\n let cleanUrl;\n\n // Check to see if we have a matching meta tag that we can make use of.\n // Moving this higher because common practice is now to use large\n // images on things like Open Graph or Twitter cards.\n // images usually have for things like Open Graph.\n const imageUrl =\n extractFromMeta(\n $,\n LEAD_IMAGE_URL_META_TAGS,\n metaCache,\n false\n );\n\n if (imageUrl) {\n cleanUrl = cleanImage(imageUrl);\n\n if (cleanUrl) return cleanUrl;\n }\n\n // Next, try to find the \"best\" image via the content.\n // We'd rather not have to fetch each image and check dimensions,\n // so try to do some analysis and determine them instead.\n const imgs = $('img', content).toArray();\n const imgScores = {};\n\n imgs.forEach((img, index) => {\n const $img = $(img);\n const src = $img.attr('src');\n\n if (!src) return;\n\n let score = scoreImageUrl(src);\n score += scoreAttr($img);\n score += scoreByParents($img);\n score += scoreBySibling($img);\n score += scoreByDimensions($img);\n score += scoreByPosition(imgs, index);\n\n imgScores[src] = score;\n });\n\n const [topUrl, topScore] =\n Reflect.ownKeys(imgScores).reduce((acc, key) =>\n imgScores[key] > acc[1] ? [key, imgScores[key]] : acc\n , [null, 0]);\n\n if (topScore > 0) {\n cleanUrl = cleanImage(topUrl);\n\n if (cleanUrl) return cleanUrl;\n }\n\n // If nothing else worked, check to see if there are any really\n // probable nodes in the doc, like <link rel=\"image_src\" />.\n for (const selector of LEAD_IMAGE_URL_SELECTORS) {\n const $node = $(selector).first();\n const src = $node.attr('src');\n if (src) {\n cleanUrl = cleanImage(src);\n if (cleanUrl) return cleanUrl;\n }\n\n const href = $node.attr('href');\n if (href) {\n cleanUrl = cleanImage(href);\n if (cleanUrl) return cleanUrl;\n }\n\n const value = $node.attr('value');\n if (value) {\n cleanUrl = cleanImage(value);\n if (cleanUrl) return cleanUrl;\n }\n }\n\n return null;\n },\n};\n\nexport default GenericLeadImageUrlExtractor;\n\n// def extract(self):\n// \"\"\"\n// # First, try to find the \"best\" image via the content.\n// # We'd rather not have to fetch each image and check dimensions,\n// # so try to do some analysis and determine them instead.\n// content = self.extractor.extract_content(return_type=\"node\")\n// imgs = content.xpath('.//img')\n// img_scores = defaultdict(int)\n// logger.debug('Scoring %d images from content', len(imgs))\n// for (i, img) in enumerate(imgs):\n// img_score = 0\n//\n// if not 'src' in img.attrib:\n// logger.debug('No src attribute found')\n// continue\n//\n// try:\n// parsed_img = urlparse(img.attrib['src'])\n// img_path = parsed_img.path.lower()\n// except ValueError:\n// logger.debug('ValueError getting img path.')\n// continue\n// logger.debug('Image path is %s', img_path)\n//\n// if constants.POSITIVE_LEAD_IMAGE_URL_HINTS_RE.match(img_path):\n// logger.debug('Positive URL hints match. Adding 20.')\n// img_score += 20\n//\n// if constants.NEGATIVE_LEAD_IMAGE_URL_HINTS_RE.match(img_path):\n// logger.debug('Negative URL hints match. Subtracting 20.')\n// img_score -= 20\n//\n// # Gifs are more often structure than photos\n// if img_path.endswith('gif'):\n// logger.debug('gif found. Subtracting 10.')\n// img_score -= 10\n//\n// # JPGs are more often photographs\n// if img_path.endswith('jpg'):\n// logger.debug('jpg found. Adding 10.')\n// img_score += 10\n//\n// # PNGs are neutral.\n//\n// # Alt attribute usually means non-presentational image.\n// if 'alt' in img.attrib and len(img.attrib['alt']) > 5:\n// logger.debug('alt attribute found. Adding 5.')\n// img_score += 5\n//\n// # Look through our parent and grandparent for figure-like\n// # container elements, give a bonus if we find them\n// parents = [img.getparent()]\n// if parents[0] is not None and parents[0].getparent() is not None:\n// parents.append(parents[0].getparent())\n// for p in parents:\n// if p.tag == 'figure':\n// logger.debug('Parent with <figure> tag found. Adding 25.')\n// img_score += 25\n//\n// p_sig = ' '.join([p.get('id', ''), p.get('class', '')])\n// if constants.PHOTO_HINTS_RE.search(p_sig):\n// logger.debug('Photo hints regex match. Adding 15.')\n// img_score += 15\n//\n// # Look at our immediate sibling and see if it looks like it's a\n// # caption. Bonus if so.\n// sibling = img.getnext()\n// if sibling is not None:\n// if sibling.tag == 'figcaption':\n// img_score += 25\n//\n// sib_sig = ' '.join([sibling.get('id', ''),\n// sibling.get('class', '')]).lower()\n// if 'caption' in sib_sig:\n// img_score += 15\n//\n// # Pull out width/height if they were set.\n// img_width = None\n// img_height = None\n// if 'width' in img.attrib:\n// try:\n// img_width = float(img.get('width'))\n// except ValueError:\n// pass\n// if 'height' in img.attrib:\n// try:\n// img_height = float(img.get('height'))\n// except ValueError:\n// pass\n//\n// # Penalty for skinny images\n// if img_width and img_width <= 50:\n// logger.debug('Skinny image found. Subtracting 50.')\n// img_score -= 50\n//\n// # Penalty for short images\n// if img_height and img_height <= 50:\n// # Wide, short images are more common than narrow, tall ones\n// logger.debug('Short image found. Subtracting 25.')\n// img_score -= 25\n//\n// if img_width and img_height and not 'sprite' in img_path:\n// area = img_width * img_height\n//\n// if area < 5000: # Smaller than 50x100\n// logger.debug('Image with small area found. Subtracting 100.')\n// img_score -= 100\n// else:\n// img_score += round(area/1000.0)\n//\n// # If the image is higher on the page than other images,\n// # it gets a bonus. Penalty if lower.\n// logger.debug('Adding page placement bonus of %d.', len(imgs)/2 - i)\n// img_score += len(imgs)/2 - i\n//\n// # Use the raw src here because we munged img_path for case\n// # insensitivity\n// logger.debug('Final score is %d.', img_score)\n// img_scores[img.attrib['src']] += img_score\n//\n// top_score = 0\n// top_url = None\n// for (url, score) in img_scores.items():\n// if score > top_score:\n// top_url = url\n// top_score = score\n//\n// if top_score > 0:\n// logger.debug('Using top score image from content. Score was %d', top_score)\n// return top_url\n//\n//\n// # If nothing else worked, check to see if there are any really\n// # probable nodes in the doc, like <link rel=\"image_src\" />.\n// logger.debug('Trying to find lead image in probable nodes')\n// for selector in constants.LEAD_IMAGE_URL_SELECTORS:\n// nodes = self.resource.extract_by_selector(selector)\n// for node in nodes:\n// clean_value = None\n// if node.attrib.get('src'):\n// clean_value = self.clean(node.attrib['src'])\n//\n// if not clean_value and node.attrib.get('href'):\n// clean_value = self.clean(node.attrib['href'])\n//\n// if not clean_value and node.attrib.get('value'):\n// clean_value = self.clean(node.attrib['value'])\n//\n// if clean_value:\n// logger.debug('Found lead image in probable nodes.')\n// logger.debug('Node was: %s', node)\n// return clean_value\n//\n// return None\n","import difflib from 'difflib';\n\nexport default function scoreSimilarity(score, articleUrl, href) {\n // Do this last and only if we have a real candidate, because it's\n // potentially expensive computationally. Compare the link to this\n // URL using difflib to get the % similarity of these URLs. On a\n // sliding scale, subtract points from this link based on\n // similarity.\n if (score > 0) {\n const similarity = new difflib.SequenceMatcher(null, articleUrl, href).ratio();\n // Subtract .1 from diff_percent when calculating modifier,\n // which means that if it's less than 10% different, we give a\n // bonus instead. Ex:\n // 3% different = +17.5 points\n // 10% different = 0 points\n // 20% different = -25 points\n const diffPercent = 1.0 - similarity;\n const diffModifier = -(250 * (diffPercent - 0.2));\n return score + diffModifier;\n }\n\n return 0;\n}\n","import { IS_DIGIT_RE } from 'utils/text/constants';\n\nexport default function scoreLinkText(linkText, pageNum) {\n // If the link text can be parsed as a number, give it a minor\n // bonus, with a slight bias towards lower numbered pages. This is\n // so that pages that might not have 'next' in their text can still\n // get scored, and sorted properly by score.\n let score = 0;\n\n if (IS_DIGIT_RE.test(linkText.trim())) {\n const linkTextAsNum = parseInt(linkText, 10);\n // If it's the first page, we already got it on the first call.\n // Give it a negative score. Otherwise, up to page 10, give a\n // small bonus.\n if (linkTextAsNum < 2) {\n score = -30;\n } else {\n score = Math.max(0, 10 - linkTextAsNum);\n }\n\n // If it appears that the current page number is greater than\n // this links page number, it's a very bad sign. Give it a big\n // penalty.\n if (pageNum && pageNum >= linkTextAsNum) {\n score -= 50;\n }\n }\n\n return score;\n}\n","export default function scorePageInLink(pageNum, isWp) {\n // page in the link = bonus. Intentionally ignore wordpress because\n // their ?p=123 link style gets caught by this even though it means\n // separate documents entirely.\n if (pageNum && !isWp) {\n return 50;\n }\n\n return 0;\n}\n","export const DIGIT_RE = /\\d/;\n\n// A list of words that, if found in link text or URLs, likely mean that\n// this link is not a next page link.\nexport const EXTRANEOUS_LINK_HINTS = [\n 'print',\n 'archive',\n 'comment',\n 'discuss',\n 'e-mail',\n 'email',\n 'share',\n 'reply',\n 'all',\n 'login',\n 'sign',\n 'single',\n 'adx',\n 'entry-unrelated',\n];\nexport const EXTRANEOUS_LINK_HINTS_RE = new RegExp(EXTRANEOUS_LINK_HINTS.join('|'), 'i');\n\n// Match any link text/classname/id that looks like it could mean the next\n// page. Things like: next, continue, >, >>, » but not >|, »| as those can\n// mean last page.\nexport const NEXT_LINK_TEXT_RE = new RegExp('(next|weiter|continue|>([^|]|$)|»([^|]|$))', 'i');\n\n// Match any link text/classname/id that looks like it is an end link: things\n// like \"first\", \"last\", \"end\", etc.\nexport const CAP_LINK_TEXT_RE = new RegExp('(first|last|end)', 'i');\n\n// Match any link text/classname/id that looks like it means the previous\n// page.\nexport const PREV_LINK_TEXT_RE = new RegExp('(prev|earl|old|new|<|«)', 'i');\n\n// Match any phrase that looks like it could be page, or paging, or pagination\nexport const PAGE_RE = new RegExp('pag(e|ing|inat)', 'i');\n\n","import { EXTRANEOUS_LINK_HINTS_RE } from '../constants';\n\nexport default function scoreExtraneousLinks(href) {\n // If the URL itself contains extraneous values, give a penalty.\n if (EXTRANEOUS_LINK_HINTS_RE.test(href)) {\n return -25;\n }\n\n return 0;\n}\n","import { range } from 'utils';\nimport {\n NEGATIVE_SCORE_RE,\n POSITIVE_SCORE_RE,\n PAGE_RE,\n} from 'utils/dom/constants';\nimport { EXTRANEOUS_LINK_HINTS_RE } from '../constants';\n\nfunction makeSig($link) {\n return `${$link.attr('class') || ''} ${$link.attr('id') || ''}`;\n}\n\nexport default function scoreByParents($link) {\n // If a parent node contains paging-like classname or id, give a\n // bonus. Additionally, if a parent_node contains bad content\n // (like 'sponsor'), give a penalty.\n let $parent = $link.parent();\n let positiveMatch = false;\n let negativeMatch = false;\n let score = 0;\n\n Array.from(range(0, 4)).forEach(() => {\n if ($parent.length === 0) {\n return;\n }\n\n const parentData = makeSig($parent, ' ');\n\n // If we have 'page' or 'paging' in our data, that's a good\n // sign. Add a bonus.\n if (!positiveMatch && PAGE_RE.test(parentData)) {\n positiveMatch = true;\n score += 25;\n }\n\n // If we have 'comment' or something in our data, and\n // we don't have something like 'content' as well, that's\n // a bad sign. Give a penalty.\n if (!negativeMatch && NEGATIVE_SCORE_RE.test(parentData)\n && EXTRANEOUS_LINK_HINTS_RE.test(parentData)) {\n if (!POSITIVE_SCORE_RE.test(parentData)) {\n negativeMatch = true;\n score -= 25;\n }\n }\n\n $parent = $parent.parent();\n });\n\n return score;\n}\n\n","import { PREV_LINK_TEXT_RE } from '../constants';\n\nexport default function scorePrevLink(linkData) {\n // If the link has something like \"previous\", its definitely\n // an old link, skip it.\n if (PREV_LINK_TEXT_RE.test(linkData)) {\n return -200;\n }\n\n return 0;\n}\n","import URL from 'url';\n\nimport {\n DIGIT_RE,\n EXTRANEOUS_LINK_HINTS_RE,\n} from '../constants';\n\nexport default function shouldScore(\n href,\n articleUrl,\n baseUrl,\n parsedUrl,\n linkText,\n previousUrls\n) {\n // skip if we've already fetched this url\n if (previousUrls.find(url => href === url) !== undefined) {\n return false;\n }\n\n // If we've already parsed this URL, or the URL matches the base\n // URL, or is empty, skip it.\n if (!href || href === articleUrl || href === baseUrl) {\n return false;\n }\n\n const { hostname } = parsedUrl;\n const { hostname: linkHost } = URL.parse(href);\n\n // Domain mismatch.\n if (linkHost !== hostname) {\n return false;\n }\n\n // If href doesn't contain a digit after removing the base URL,\n // it's certainly not the next page.\n const fragment = href.replace(baseUrl, '');\n if (!DIGIT_RE.test(fragment)) {\n return false;\n }\n\n // This link has extraneous content (like \"comment\") in its link\n // text, so we skip it.\n if (EXTRANEOUS_LINK_HINTS_RE.test(linkText)) {\n return false;\n }\n\n // Next page link text is never long, skip if it is too long.\n if (linkText.length > 25) {\n return false;\n }\n\n return true;\n}\n\n","export default function scoreBaseUrl(href, baseRegex) {\n // If the baseUrl isn't part of this URL, penalize this\n // link. It could still be the link, but the odds are lower.\n // Example:\n // http://www.actionscript.org/resources/articles/745/1/JavaScript-and-VBScript-Injection-in-ActionScript-3/Page1.html\n if (!baseRegex.test(href)) {\n return -25;\n }\n\n return 0;\n}\n","import { NEXT_LINK_TEXT_RE } from '../constants';\n\nexport default function scoreNextLinkText(linkData) {\n // Things like \"next\", \">>\", etc.\n if (NEXT_LINK_TEXT_RE.test(linkData)) {\n return 50;\n }\n\n return 0;\n}\n","import {\n NEXT_LINK_TEXT_RE,\n CAP_LINK_TEXT_RE,\n} from '../constants';\n\nexport default function scoreCapLinks(linkData) {\n // Cap links are links like \"last\", etc.\n if (CAP_LINK_TEXT_RE.test(linkData)) {\n // If we found a link like \"last\", but we've already seen that\n // this link is also \"next\", it's fine. If it's not been\n // previously marked as \"next\", then it's probably bad.\n // Penalize.\n if (NEXT_LINK_TEXT_RE.test(linkData)) {\n return -65;\n }\n }\n\n return 0;\n}\n","import URL from 'url';\n\nimport { isWordpress } from 'utils/dom';\nimport {\n removeAnchor,\n pageNumFromUrl,\n} from 'utils/text';\n\nimport {\n scoreSimilarity,\n scoreLinkText,\n scorePageInLink,\n scoreExtraneousLinks,\n scoreByParents,\n scorePrevLink,\n shouldScore,\n scoreBaseUrl,\n scoreCapLinks,\n scoreNextLinkText,\n} from './utils';\n\nexport function makeBaseRegex(baseUrl) {\n return new RegExp(`^${baseUrl}`, 'i');\n}\n\nfunction makeSig($link, linkText) {\n return `${linkText || $link.text()} ${$link.attr('class') || ''} ${$link.attr('id') || ''}`;\n}\n\nexport default function scoreLinks({\n links,\n articleUrl,\n baseUrl,\n parsedUrl,\n $,\n previousUrls = [],\n}) {\n parsedUrl = parsedUrl || URL.parse(articleUrl);\n const baseRegex = makeBaseRegex(baseUrl);\n const isWp = isWordpress($);\n\n // Loop through all links, looking for hints that they may be next-page\n // links. Things like having \"page\" in their textContent, className or\n // id, or being a child of a node with a page-y className or id.\n //\n // After we do that, assign each page a score, and pick the one that\n // looks most like the next page link, as long as its score is strong\n // enough to have decent confidence.\n const scoredPages = links.reduce((possiblePages, link) => {\n // Remove any anchor data since we don't do a good job\n // standardizing URLs (it's hard), we're going to do\n // some checking with and without a trailing slash\n const href = removeAnchor(link.attribs.href);\n const $link = $(link);\n const linkText = $link.text();\n\n if (!shouldScore(href, articleUrl, baseUrl, parsedUrl, linkText, previousUrls)) {\n return possiblePages;\n }\n\n // ## PASSED THE FIRST-PASS TESTS. Start scoring. ##\n if (!possiblePages[href]) {\n possiblePages[href] = {\n score: 0,\n linkText,\n href,\n };\n } else {\n possiblePages[href].linkText = `${possiblePages[href].linkText}|${linkText}`;\n }\n\n const possiblePage = possiblePages[href];\n const linkData = makeSig($link, linkText);\n const pageNum = pageNumFromUrl(href);\n\n let score = scoreBaseUrl(href, baseRegex);\n score += scoreNextLinkText(linkData);\n score += scoreCapLinks(linkData);\n score += scorePrevLink(linkData);\n score += scoreByParents($link);\n score += scoreExtraneousLinks(href);\n score += scorePageInLink(pageNum, isWp);\n score += scoreLinkText(linkText, pageNum);\n score += scoreSimilarity(score, articleUrl, href);\n\n possiblePage.score = score;\n\n return possiblePages;\n }, {});\n\n return Reflect.ownKeys(scoredPages).length === 0 ? null : scoredPages;\n}\n","import URL from 'url';\n\nimport {\n articleBaseUrl,\n removeAnchor,\n} from 'utils/text';\nimport scoreLinks from './scoring/score-links';\n\n// Looks for and returns next page url\n// for multi-page articles\nconst GenericNextPageUrlExtractor = {\n extract({ $, url, parsedUrl, previousUrls = [] }) {\n parsedUrl = parsedUrl || URL.parse(url);\n\n const articleUrl = removeAnchor(url);\n const baseUrl = articleBaseUrl(url, parsedUrl);\n\n const links = $('a[href]').toArray();\n\n const scoredLinks = scoreLinks({\n links,\n articleUrl,\n baseUrl,\n parsedUrl,\n $,\n previousUrls,\n });\n\n // If no links were scored, return null\n if (!scoredLinks) return null;\n\n // now that we've scored all possible pages,\n // find the biggest one.\n const topPage = Reflect.ownKeys(scoredLinks).reduce((acc, link) => {\n const scoredLink = scoredLinks[link];\n return scoredLink.score > acc.score ? scoredLink : acc;\n }, { score: -100 });\n\n // If the score is less than 50, we're not confident enough to use it,\n // so we fail.\n if (topPage.score >= 50) {\n return topPage.href;\n }\n\n return null;\n },\n};\n\n\nexport default GenericNextPageUrlExtractor;\n","export const CANONICAL_META_SELECTORS = [\n 'og:url',\n];\n","import URL from 'url';\nimport { extractFromMeta } from 'utils/dom';\n\nimport { CANONICAL_META_SELECTORS } from './constants';\n\nfunction parseDomain(url) {\n const parsedUrl = URL.parse(url);\n const { hostname } = parsedUrl;\n return hostname;\n}\n\nfunction result(url) {\n return {\n url,\n domain: parseDomain(url),\n };\n}\n\nconst GenericUrlExtractor = {\n extract({ $, url, metaCache }) {\n const $canonical = $('link[rel=canonical]');\n if ($canonical.length !== 0) {\n const href = $canonical.attr('href');\n if (href) {\n return result(href);\n }\n }\n\n const metaUrl = extractFromMeta($, CANONICAL_META_SELECTORS, metaCache);\n if (metaUrl) {\n return result(metaUrl);\n }\n\n return result(url);\n },\n\n};\n\nexport default GenericUrlExtractor;\n","export const EXCERPT_META_SELECTORS = [\n 'og:description',\n 'twitter:description',\n];\n","import ellipsize from 'ellipsize';\n\nimport {\n extractFromMeta,\n stripTags,\n} from 'utils/dom';\n\nimport { EXCERPT_META_SELECTORS } from './constants';\n\nexport function clean(content, $, maxLength = 200) {\n content = content.replace(/[\\s\\n]+/g, ' ').trim();\n return ellipsize(content, maxLength, { ellipse: '…' });\n}\n\nconst GenericExcerptExtractor = {\n extract({ $, content, metaCache }) {\n const excerpt = extractFromMeta($, EXCERPT_META_SELECTORS, metaCache);\n if (excerpt) {\n return clean(stripTags(excerpt, $));\n }\n // Fall back to excerpting from the extracted content\n const maxLength = 200;\n const shortContent = content.slice(0, maxLength * 5);\n return clean($(shortContent).text(), $, maxLength);\n },\n};\n\nexport default GenericExcerptExtractor;\n","import cheerio from 'cheerio';\n\nimport { normalizeSpaces } from 'utils/text';\n\nconst GenericWordCountExtractor = {\n extract({ content }) {\n const $ = cheerio.load(content);\n\n const text = normalizeSpaces($('div').first().text());\n return text.split(/\\s/).length;\n },\n};\n\nexport default GenericWordCountExtractor;\n","import cheerio from 'cheerio';\nimport stringDirection from 'string-direction';\n\nimport GenericContentExtractor from './content/extractor';\nimport GenericTitleExtractor from './title/extractor';\nimport GenericAuthorExtractor from './author/extractor';\nimport GenericDatePublishedExtractor from './date-published/extractor';\nimport GenericDekExtractor from './dek/extractor';\nimport GenericLeadImageUrlExtractor from './lead-image-url/extractor';\nimport GenericNextPageUrlExtractor from './next-page-url/extractor';\nimport GenericUrlExtractor from './url/extractor';\nimport GenericExcerptExtractor from './excerpt/extractor';\nimport GenericWordCountExtractor from './word-count/extractor';\n\nconst GenericExtractor = {\n // This extractor is the default for all domains\n domain: '*',\n title: GenericTitleExtractor.extract,\n date_published: GenericDatePublishedExtractor.extract,\n author: GenericAuthorExtractor.extract,\n content: GenericContentExtractor.extract.bind(GenericContentExtractor),\n lead_image_url: GenericLeadImageUrlExtractor.extract,\n dek: GenericDekExtractor.extract,\n next_page_url: GenericNextPageUrlExtractor.extract,\n url_and_domain: GenericUrlExtractor.extract,\n excerpt: GenericExcerptExtractor.extract,\n word_count: GenericWordCountExtractor.extract,\n direction: ({ title }) => stringDirection.getDirection(title),\n\n extract(options) {\n const { html } = options;\n\n if (html) {\n const $ = cheerio.load(html);\n options.$ = $;\n }\n\n const title = this.title(options);\n const date_published = this.date_published(options);\n const author = this.author(options);\n const content = this.content({ ...options, title });\n const lead_image_url = this.lead_image_url({ ...options, content });\n const dek = this.dek({ ...options, content });\n const next_page_url = this.next_page_url(options);\n const excerpt = this.excerpt({ ...options, content });\n const word_count = this.word_count({ ...options, content });\n const direction = this.direction({ title });\n const { url, domain } = this.url_and_domain(options);\n\n return {\n title,\n author,\n date_published: date_published || null,\n dek,\n lead_image_url,\n content,\n next_page_url,\n url,\n domain,\n excerpt,\n word_count,\n direction,\n };\n },\n};\n\nexport default GenericExtractor;\n","import URL from 'url';\n\nimport Extractors from './all';\nimport GenericExtractor from './generic';\n\nexport default function getExtractor(url, parsedUrl) {\n parsedUrl = parsedUrl || URL.parse(url);\n const { hostname } = parsedUrl;\n const baseDomain = hostname.split('.').slice(-2).join('.');\n\n return Extractors[hostname] || Extractors[baseDomain] || GenericExtractor;\n}\n","import Cleaners from 'cleaners';\nimport { convertNodeTo } from 'utils/dom';\nimport GenericExtractor from './generic';\n\n// Remove elements by an array of selectors\nexport function cleanBySelectors($content, $, { clean }) {\n if (!clean) return $content;\n\n $(clean.join(','), $content).remove();\n\n return $content;\n}\n\n// Transform matching elements\nexport function transformElements($content, $, { transforms }) {\n if (!transforms) return $content;\n\n Reflect.ownKeys(transforms).forEach((key) => {\n const $matches = $(key, $content);\n const value = transforms[key];\n\n // If value is a string, convert directly\n if (typeof value === 'string') {\n $matches.each((index, node) => {\n convertNodeTo($(node), $, transforms[key]);\n });\n } else if (typeof value === 'function') {\n // If value is function, apply function to node\n $matches.each((index, node) => {\n const result = value($(node), $);\n // If function returns a string, convert node to that value\n if (typeof result === 'string') {\n convertNodeTo($(node), $, result);\n }\n });\n }\n });\n\n return $content;\n}\n\nfunction findMatchingSelector($, selectors) {\n return selectors.find((selector) => {\n if (Array.isArray(selector)) {\n const [s, attr] = selector;\n return $(s).length === 1 && $(s).attr(attr) && $(s).attr(attr).trim() !== '';\n }\n\n return $(selector).length === 1 && $(selector).text().trim() !== '';\n });\n}\n\nexport function select(opts) {\n const { $, type, extractionOpts, extractHtml = false } = opts;\n // Skip if there's not extraction for this type\n if (!extractionOpts) return null;\n\n // If a string is hardcoded for a type (e.g., Wikipedia\n // contributors), return the string\n if (typeof extractionOpts === 'string') return extractionOpts;\n\n const { selectors, defaultCleaner = true } = extractionOpts;\n\n const matchingSelector = findMatchingSelector($, selectors);\n\n if (!matchingSelector) return null;\n\n // Declaring result; will contain either\n // text or html, which will be cleaned\n // by the appropriate cleaner type\n\n // If the selector type requests html as its return type\n // transform and clean the element with provided selectors\n if (extractHtml) {\n let $content = $(matchingSelector);\n\n // Wrap in div so transformation can take place on root element\n $content.wrap($('<div></div>'));\n $content = $content.parent();\n\n $content = transformElements($content, $, extractionOpts);\n $content = cleanBySelectors($content, $, extractionOpts);\n\n $content = Cleaners[type]($content, { ...opts, defaultCleaner });\n\n return $.html($content);\n }\n\n let result;\n\n // if selector is an array (e.g., ['img', 'src']),\n // extract the attr\n if (Array.isArray(matchingSelector)) {\n const [selector, attr] = matchingSelector;\n result = $(selector).attr(attr).trim();\n } else {\n result = $(matchingSelector).text().trim();\n }\n\n // Allow custom extractor to skip default cleaner\n // for this type; defaults to true\n if (defaultCleaner) {\n return Cleaners[type](result, opts);\n }\n\n return result;\n}\n\nfunction extractResult(opts) {\n const { type, extractor, fallback = true } = opts;\n\n const result = select({ ...opts, extractionOpts: extractor[type] });\n\n // If custom parser succeeds, return the result\n if (result) {\n return result;\n }\n\n // If nothing matches the selector, and fallback is enabled,\n // run the Generic extraction\n if (fallback) return GenericExtractor[type](opts);\n\n return null;\n}\n\nconst RootExtractor = {\n extract(extractor = GenericExtractor, opts) {\n const { contentOnly, extractedTitle } = opts;\n // This is the generic extractor. Run its extract method\n if (extractor.domain === '*') return extractor.extract(opts);\n\n opts = {\n ...opts,\n extractor,\n };\n\n if (contentOnly) {\n const content = extractResult({\n ...opts, type: 'content', extractHtml: true, title: extractedTitle,\n });\n return {\n content,\n };\n }\n const title = extractResult({ ...opts, type: 'title' });\n const date_published = extractResult({ ...opts, type: 'date_published' });\n const author = extractResult({ ...opts, type: 'author' });\n const next_page_url = extractResult({ ...opts, type: 'next_page_url' });\n const content = extractResult({\n ...opts, type: 'content', extractHtml: true, title,\n });\n const lead_image_url = extractResult({ ...opts, type: 'lead_image_url', content });\n const excerpt = extractResult({ ...opts, type: 'excerpt', content });\n const dek = extractResult({ ...opts, type: 'dek', content, excerpt });\n const word_count = extractResult({ ...opts, type: 'word_count', content });\n const direction = extractResult({ ...opts, type: 'direction', title });\n const { url, domain } =\n extractResult({ ...opts, type: 'url_and_domain' }) || { url: null, domain: null };\n\n return {\n title,\n content,\n author,\n date_published,\n lead_image_url,\n dek,\n next_page_url,\n url,\n domain,\n excerpt,\n word_count,\n direction,\n };\n },\n};\n\nexport default RootExtractor;\n","import { removeAnchor } from 'utils/text';\nimport RootExtractor from 'extractors/root-extractor';\nimport GenericExtractor from 'extractors/generic';\nimport Resource from 'resource';\n\nexport default async function collectAllPages(\n {\n next_page_url,\n html,\n $,\n metaCache,\n result,\n Extractor,\n title,\n url,\n }\n) {\n // At this point, we've fetched just the first page\n let pages = 1;\n const previousUrls = [removeAnchor(url)];\n\n // If we've gone over 26 pages, something has\n // likely gone wrong.\n while (next_page_url && pages < 26) {\n pages += 1;\n $ = await Resource.create(next_page_url);\n html = $.html();\n\n const extractorOpts = {\n url: next_page_url,\n html,\n $,\n metaCache,\n contentOnly: true,\n extractedTitle: title,\n previousUrls,\n };\n\n const nextPageResult = RootExtractor.extract(Extractor, extractorOpts);\n\n previousUrls.push(next_page_url);\n result = {\n ...result,\n content: `\n ${result.content}\n <hr>\n <h4>Page ${pages}</h4>\n ${nextPageResult.content}\n `,\n };\n\n next_page_url = nextPageResult.next_page_url;\n }\n\n const word_count = GenericExtractor.word_count({ content: `<div>${result.content}</div>` });\n return {\n ...result,\n total_pages: pages,\n pages_rendered: pages,\n word_count,\n };\n}\n","import URL from 'url';\n\nimport Resource from 'resource';\nimport {\n validateUrl,\n Errors,\n} from 'utils';\nimport getExtractor from 'extractors/get-extractor';\nimport RootExtractor from 'extractors/root-extractor';\nimport collectAllPages from 'extractors/collect-all-pages';\n\nconst Mercury = {\n async parse(url, html, opts = {}) {\n const {\n fetchAllPages = true,\n fallback = true,\n } = opts;\n\n const parsedUrl = URL.parse(url);\n\n if (!validateUrl(parsedUrl)) {\n return Errors.badUrl;\n }\n\n const Extractor = getExtractor(url, parsedUrl);\n // console.log(`Using extractor for ${Extractor.domain}`);\n\n const $ = await Resource.create(url, html, parsedUrl);\n\n // If we found an error creating the resource, return that error\n if ($.error) {\n return $;\n }\n\n html = $.html();\n\n // Cached value of every meta name in our document.\n // Used when extracting title/author/date_published/dek\n const metaCache = $('meta').map((_, node) => $(node).attr('name')).toArray();\n\n let result = RootExtractor.extract(Extractor, { url, html, $, metaCache, parsedUrl, fallback });\n const { title, next_page_url } = result;\n\n // Fetch more pages if next_page_url found\n if (fetchAllPages && next_page_url) {\n result = await collectAllPages(\n {\n Extractor,\n next_page_url,\n html,\n $,\n metaCache,\n result,\n title,\n url,\n }\n );\n } else {\n result = {\n ...result,\n total_pages: 1,\n rendered_pages: 1,\n };\n }\n\n return result;\n },\n\n // A convenience method for getting a resource\n // to work with, e.g., for custom extractor generator\n async fetchResource(url) {\n return await Resource.create(url);\n },\n\n};\n\nexport default Mercury;\n"],"names":["range","start","end","validateUrl","hostname","Errors","REQUEST_HEADERS","FETCH_TIMEOUT","BAD_CONTENT_TYPES","BAD_CONTENT_TYPES_RE","RegExp","join","MAX_CONTENT_LENGTH","get","options","resolve","reject","err","response","body","validateResponse","parseNon2xx","statusMessage","statusCode","Error","error","headers","contentType","contentLength","test","url","parsedUrl","URL","parse","encodeURI","badUrl","fetchResource","convertMetaProp","$","from","to","each","_","node","$node","value","attr","removeAttr","normalizeMetaTags","IS_LINK","IS_IMAGE","TAGS_TO_REMOVE","convertLazyLoadedImages","img","attribs","forEach","isComment","index","type","cleanComments","root","find","contents","filter","remove","clean","Resource","preparedResponse","validResponse","result","generateDoc","content","includes","cheerio","load","normalizeWhitespace","children","length","merge","extractor","domains","reduce","acc","domain","mergeSupportedDomains","supportedDomains","NYMagExtractor","$children","tagName","BloggerExtractor","WikipediaExtractor","$parent","parents","prepend","TwitterExtractor","tweets","$tweetContainer","append","replaceWith","NYTimesExtractor","src","width","replace","TheAtlanticExtractor","NewYorkerExtractor","WiredExtractor","MSNExtractor","YahooExtractor","BuzzfeedExtractor","WikiaExtractor","LittleThingsExtractor","PoliticoExtractor","DeadspinExtractor","youtubeId","split","BroadwayWorldExtractor","ApartmentTherapyExtractor","data","JSON","sources","$img","MediumExtractor","ytRe","thumb","decodeURIComponent","match","clone","Extractors","SPACER_RE","KEEP_CLASS","KEEP_SELECTORS","STRIP_OUTPUT_TAGS","REMOVE_ATTRS","REMOVE_ATTR_SELECTORS","map","selector","REMOVE_ATTR_LIST","WHITELIST_ATTRS","WHITELIST_ATTRS_RE","REMOVE_EMPTY_TAGS","REMOVE_EMPTY_SELECTORS","tag","CLEAN_CONDITIONALLY_TAGS","HEADER_TAGS","HEADER_TAG_LIST","UNLIKELY_CANDIDATES_BLACKLIST","UNLIKELY_CANDIDATES_WHITELIST","DIV_TO_P_BLOCK_TAGS","NON_TOP_CANDIDATE_TAGS","NON_TOP_CANDIDATE_TAGS_RE","PHOTO_HINTS","PHOTO_HINTS_RE","POSITIVE_SCORE_HINTS","POSITIVE_SCORE_RE","NEGATIVE_SCORE_HINTS","NEGATIVE_SCORE_RE","IS_WP_SELECTOR","EXTRANEOUS_LINK_HINTS","EXTRANEOUS_LINK_HINTS_RE","PAGE_RE","BLOCK_LEVEL_TAGS","BLOCK_LEVEL_TAGS_RE","candidatesBlacklist","CANDIDATES_BLACKLIST","candidatesWhitelist","CANDIDATES_WHITELIST","stripUnlikelyCandidates","not","classes","id","classAndId","brsToPs","collapsing","element","nextElement","next","paragraphize","br","sibling","nextSibling","p","appendTo","convertDivs","div","$div","convertable","convertSpans","span","$span","convertToParagraphs","convertNodeTo","attribString","key","cleanForHeight","height","parseInt","removeSpacers","cleanImages","$article","markToKeep","article","tags","protocol","addClass","stripJunkTags","removeClass","cleanHOnes","$hOnes","removeAllButWhitelist","cleanAttributes","parent","removeEmpty","$p","text","trim","HNEWS_CONTENT_SELECTORS","READABILITY_ASSET","PARAGRAPH_SCORE_TAGS","CHILD_CONTENT_TAGS","BAD_TAGS","getWeight","score","getScore","parseFloat","scoreCommas","idkRe","scoreLength","textLength","chunks","lengthBonus","Math","min","max","scoreParagraph","slice","setScore","addScore","amount","getOrInitScore","e","addToParent","weightNodes","scoreNode","addScoreTo","scorePs","rawScore","scoreContent","parentSelector","childSelector","NORMALIZE_RE","normalizeSpaces","extractFromUrl","regexList","matchRe","re","exec","PAGE_IN_HREF_RE","HAS_ALPHA_RE","IS_ALPHA_RE","IS_DIGIT_RE","pageNumFromUrl","matches","pageNum","removeAnchor","isGoodSegment","segment","firstSegmentHasLetters","goodSegment","toLowerCase","articleBaseUrl","parsed","host","path","cleanedSegments","reverse","rawSegment","possibleSegment","fileExt","push","SENTENCE_END_RE","hasSentenceEnd","excerptContent","words","mergeSiblings","$candidate","topScore","siblingScoreThreshold","wrappingDiv","$sibling","siblingScore","contentBonus","density","linkDensity","newScore","siblingContent","siblingContentLength","findTopCandidate","first","removeUnlessContent","weight","hasClass","pCount","inputCount","imgCount","nodeIsList","previousNode","prev","scriptCount","cleanTags","cleanHeaders","title","header","$header","prevAll","rewriteTopLevel","absolutize","rootUrl","$content","absoluteUrl","makeLinksAbsolute","totalTextLength","linkText","linkLength","extractFromMeta","metaNames","cachedNames","foundNames","indexOf","name","nodes","values","toArray","metaValue","stripTags","isGoodNode","maxChildren","withinComment","extractFromSelectors","selectors","textOnly","html","cleanText","commentParent","class","undefined","nodeIsSufficient","isWordpress","CLEAN_AUTHOR_RE","TEXT_LINK_RE","MS_DATE_STRING","SEC_DATE_STRING","CLEAN_DATE_STRING_RE","TIME_MERIDIAN_SPACE_RE","TIME_MERIDIAN_DOTS_RE","months","allMonths","timestamp1","timestamp2","SPLIT_DATE_STRING","TITLE_SPLITTERS_RE","DOMAIN_ENDINGS_RE","cleanAuthor","author","leadImageUrl","validUrl","isWebUri","cleanDek","dek","excerpt","dekText","cleanDateString","dateString","cleanDatePublished","date","moment","Date","isValid","toISOString","extractCleanNode","cleanConditionally","defaultCleaner","cleanTitle","resolveSplitTitle","h1","extractBreadcrumbTitle","splitTitle","termCounts","titleText","maxTerm","termCount","splitEnds","longestEnd","cleanDomainFromTitle","nakedDomain","startSlug","startSlugRatio","wuzzy","levenshtein","endSlug","endSlugRatio","newTitle","Cleaners","cleanImage","cleanContent","extractBestNode","opts","$topCandidate","GenericContentExtractor","defaultOpts","getContentNode","cleanAndReturnNode","k","STRONG_TITLE_META_TAGS","WEAK_TITLE_META_TAGS","STRONG_TITLE_SELECTORS","WEAK_TITLE_SELECTORS","GenericTitleExtractor","metaCache","AUTHOR_META_TAGS","AUTHOR_MAX_LENGTH","AUTHOR_SELECTORS","bylineRe","BYLINE_SELECTORS_RE","GenericAuthorExtractor","regex","DATE_PUBLISHED_META_TAGS","DATE_PUBLISHED_SELECTORS","abbrevMonthsStr","DATE_PUBLISHED_URL_RES","GenericDatePublishedExtractor","datePublished","GenericDekExtractor","LEAD_IMAGE_URL_META_TAGS","LEAD_IMAGE_URL_SELECTORS","POSITIVE_LEAD_IMAGE_URL_HINTS","POSITIVE_LEAD_IMAGE_URL_HINTS_RE","NEGATIVE_LEAD_IMAGE_URL_HINTS","NEGATIVE_LEAD_IMAGE_URL_HINTS_RE","GIF_RE","JPG_RE","getSig","scoreImageUrl","scoreAttr","scoreByParents","$figParent","$gParent","scoreBySibling","scoreByDimensions","area","round","scoreByPosition","$imgs","GenericLeadImageUrlExtractor","cleanUrl","imageUrl","imgs","imgScores","topUrl","href","scoreSimilarity","articleUrl","similarity","difflib","SequenceMatcher","ratio","diffPercent","diffModifier","scoreLinkText","linkTextAsNum","scorePageInLink","isWp","DIGIT_RE","NEXT_LINK_TEXT_RE","CAP_LINK_TEXT_RE","PREV_LINK_TEXT_RE","scoreExtraneousLinks","makeSig","$link","positiveMatch","negativeMatch","parentData","scorePrevLink","linkData","shouldScore","baseUrl","previousUrls","linkHost","fragment","scoreBaseUrl","baseRegex","scoreNextLinkText","scoreCapLinks","makeBaseRegex","scoreLinks","links","scoredPages","possiblePages","link","possiblePage","GenericNextPageUrlExtractor","scoredLinks","topPage","scoredLink","CANONICAL_META_SELECTORS","parseDomain","GenericUrlExtractor","$canonical","metaUrl","EXCERPT_META_SELECTORS","maxLength","ellipsize","ellipse","GenericExcerptExtractor","shortContent","GenericWordCountExtractor","GenericExtractor","extract","bind","stringDirection","getDirection","date_published","lead_image_url","next_page_url","word_count","direction","url_and_domain","getExtractor","baseDomain","cleanBySelectors","transformElements","transforms","$matches","findMatchingSelector","Array","isArray","s","select","extractionOpts","extractHtml","matchingSelector","wrap","extractResult","fallback","RootExtractor","contentOnly","extractedTitle","Extractor","pages","create","extractorOpts","nextPageResult","collectAllPages","Mercury","fetchAllPages"],"mappings":"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"} \ No newline at end of file diff --git a/src/extractors/all.js b/src/extractors/all.js index 4769f342..d081dbae 100644 --- a/src/extractors/all.js +++ b/src/extractors/all.js @@ -1,3 +1,4 @@ +import mergeSupportedDomains from 'utils/merge-supported-domains'; import { NYMagExtractor } from './custom/nymag.com'; import { BloggerExtractor } from './custom/blogspot.com'; import { WikipediaExtractor } from './custom/wikipedia.org'; @@ -32,15 +33,10 @@ const Extractors = { 'fandom.wikia.com': WikiaExtractor, 'www.littlethings.com': LittleThingsExtractor, 'www.politico.com': PoliticoExtractor, - 'deadspin.com': DeadspinExtractor, - 'jezebel.com': DeadspinExtractor, - 'lifehacker.com': DeadspinExtractor, - 'kotaku.com': DeadspinExtractor, - 'gizmodo.com': DeadspinExtractor, - 'jalopnik.com': DeadspinExtractor, + ...mergeSupportedDomains(DeadspinExtractor), 'www.broadwayworld.com': BroadwayWorldExtractor, 'www.apartmenttherapy.com': ApartmentTherapyExtractor, - 'medium.com': MediumExtractor, + ...mergeSupportedDomains(MediumExtractor), }; export default Extractors; diff --git a/src/extractors/custom/deadspin.com/index.js b/src/extractors/custom/deadspin.com/index.js index 29772a10..14a20973 100644 --- a/src/extractors/custom/deadspin.com/index.js +++ b/src/extractors/custom/deadspin.com/index.js @@ -1,5 +1,15 @@ export const DeadspinExtractor = { domain: 'deadspin.com', + + supportedDomains: [ + 'jezebel.com', + 'lifehacker.com', + 'kotaku.com', + 'gizmodo.com', + 'jalopnik.com', + 'kinja.com', + ], + title: { selectors: [ 'h1.headline', diff --git a/src/extractors/custom/medium.com/index.js b/src/extractors/custom/medium.com/index.js index 2e960bbb..1e3a84b0 100644 --- a/src/extractors/custom/medium.com/index.js +++ b/src/extractors/custom/medium.com/index.js @@ -1,5 +1,10 @@ export const MediumExtractor = { domain: 'medium.com', + + supportedDomains: [ + 'trackchanges.postlight.com', + ], + title: { selectors: [ 'h1', diff --git a/src/utils/merge-supported-domains.js b/src/utils/merge-supported-domains.js new file mode 100644 index 00000000..b0424cfc --- /dev/null +++ b/src/utils/merge-supported-domains.js @@ -0,0 +1,13 @@ +const merge = (extractor, domains) => ( + domains.reduce((acc, domain) => { + acc[domain] = extractor; + return acc; + }, {}) +); + +export default function mergeSupportedDomains(extractor) { + return extractor.supportedDomains ? + merge(extractor, [extractor.domain, ...extractor.supportedDomains]) + : + merge(extractor, [extractor.domain]); +} diff --git a/src/utils/merge-supported-domains.test.js b/src/utils/merge-supported-domains.test.js new file mode 100644 index 00000000..44e6ca2c --- /dev/null +++ b/src/utils/merge-supported-domains.test.js @@ -0,0 +1,31 @@ +import assert from 'assert'; + +import mergeSupportedDomains from './merge-supported-domains'; + +describe('mergeSupportedDomains(extractor, domains)', () => { + it('returns an object w/domains as keys and extractor as value', () => { + const extractor = { + domain: 'foo.com', + supportedDomains: ['example.com'], + }; + const expected = { + 'foo.com': extractor, + 'example.com': extractor, + }; + + const result = mergeSupportedDomains(extractor); + assert.deepEqual(result, expected); + }); + + it('returns an object w/single domain if no supportedDomains', () => { + const extractor = { + domain: 'foo.com', + }; + const expected = { + 'foo.com': extractor, + }; + + const result = mergeSupportedDomains(extractor); + assert.deepEqual(result, expected); + }); +});