Skip to content

Commit 5c4bf32

Browse files
committed
do not pass article instance around everywhere take 1
1 parent 67f5ab4 commit 5c4bf32

7 files changed

Lines changed: 171 additions & 114 deletions

File tree

goose/cleaners.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,17 @@
2525

2626
class DocumentCleaner(object):
2727

28-
def __init__(self, config):
28+
def __init__(self, config, article):
29+
# config
2930
self.config = config
31+
3032
# parser
3133
self.parser = self.config.get_parser()
34+
35+
# article
36+
self.article = article
37+
38+
# nodes to remove regexp
3239
self.remove_nodes_re = (
3340
"^side$|combx|retweet|mediaarticlerelated|menucontainer|navbar"
3441
"|comment|PopularQuestions|contact|foot|footer|Footer|footnote"
@@ -57,9 +64,9 @@ def __init__(self, config):
5764
.append("\t")\
5865
.append("^\\s+$")
5966

60-
def clean(self, article):
67+
def clean(self):
6168

62-
doc_to_clean = article.doc
69+
doc_to_clean = self.article.doc
6370
doc_to_clean = self.clean_article_tags(doc_to_clean)
6471
doc_to_clean = self.clean_em_tags(doc_to_clean)
6572
doc_to_clean = self.remove_drop_caps(doc_to_clean)

goose/crawler.py

Lines changed: 82 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -46,100 +46,136 @@ def __init__(self, config, url, raw_html):
4646
class Crawler(object):
4747

4848
def __init__(self, config):
49+
# config
4950
self.config = config
5051
# parser
5152
self.parser = self.config.get_parser()
53+
54+
# article
55+
self.article = Article()
56+
57+
# init the extractor
58+
self.extractor = self.get_extractor()
59+
60+
# init the document cleaner
61+
self.cleaner = self.get_cleaner()
62+
63+
# init the output formatter
64+
self.formatter = self.get_formatter()
65+
66+
# video extractor
67+
self.video_extractor = self.get_video_extractor()
68+
69+
# image extrator
70+
self.image_extractor = self.get_image_extractor()
71+
72+
# TODO : log prefix
5273
self.logPrefix = "crawler:"
5374

5475
def crawl(self, crawl_candidate):
55-
article = Article()
5676

77+
# parser candidate
5778
parse_candidate = self.get_parse_candidate(crawl_candidate)
79+
80+
# raw html
5881
raw_html = self.get_html(crawl_candidate, parse_candidate)
5982

6083
if raw_html is None:
61-
return article
84+
return self.article
6285

86+
# create document
6387
doc = self.get_document(raw_html)
6488

65-
extractor = self.get_extractor()
66-
document_cleaner = self.get_document_cleaner()
67-
output_formatter = self.get_output_formatter()
68-
6989
# article
70-
article.final_url = parse_candidate.url
71-
article.link_hash = parse_candidate.link_hash
72-
article.raw_html = raw_html
73-
article.doc = doc
74-
article.raw_doc = deepcopy(doc)
75-
article.title = extractor.get_title(article)
90+
self.article.final_url = parse_candidate.url
91+
self.article.link_hash = parse_candidate.link_hash
92+
self.article.raw_html = raw_html
93+
self.article.doc = doc
94+
self.article.raw_doc = deepcopy(doc)
7695
# TODO
77-
# article.publish_date = config.publishDateExtractor.extract(doc)
78-
# article.additional_data = config.get_additionaldata_extractor.extract(doc)
79-
article.meta_lang = extractor.get_meta_lang(article)
80-
article.meta_favicon = extractor.get_favicon(article)
81-
article.meta_description = extractor.get_meta_description(article)
82-
article.meta_keywords = extractor.get_meta_keywords(article)
83-
article.canonical_link = extractor.get_canonical_link(article)
84-
article.domain = extractor.get_domain(article.final_url)
85-
article.tags = extractor.extract_tags(article)
86-
# # before we do any calcs on the body itself let's clean up the document
87-
article.doc = document_cleaner.clean(article)
96+
# self.article.publish_date = config.publishDateExtractor.extract(doc)
97+
# self.article.additional_data = config.get_additionaldata_extractor.extract(doc)
98+
self.article.title = self.extractor.get_title()
99+
self.article.meta_lang = self.extractor.get_meta_lang()
100+
self.article.meta_favicon = self.extractor.get_favicon()
101+
self.article.meta_description = self.extractor.get_meta_description()
102+
self.article.meta_keywords = self.extractor.get_meta_keywords()
103+
self.article.canonical_link = self.extractor.get_canonical_link()
104+
self.article.domain = self.extractor.get_domain()
105+
self.article.tags = self.extractor.extract_tags()
106+
107+
# before we do any calcs on the body itself let's clean up the document
108+
self.article.doc = self.cleaner.clean()
88109

89110
# big stuff
90-
article.top_node = extractor.calculate_best_node(article)
91-
if article.top_node is not None:
111+
self.article.top_node = self.extractor.calculate_best_node()
112+
113+
# if we have a top node
114+
# let's process it
115+
if self.article.top_node is not None:
116+
92117
# video handeling
93-
video_extractor = self.get_video_extractor(article)
94-
video_extractor.get_videos()
118+
self.video_extractor.get_videos()
119+
95120
# image handeling
96121
if self.config.enable_image_fetching:
97-
image_extractor = self.get_image_extractor(article)
98-
article.top_image = image_extractor.get_best_image(article.raw_doc, article.top_node)
122+
self.get_image()
123+
99124
# post cleanup
100-
article.top_node = extractor.post_cleanup(article.top_node)
125+
self.article.top_node = self.extractor.post_cleanup()
126+
101127
# clean_text
102-
article.cleaned_text = output_formatter.get_formatted_text(article)
128+
self.article.cleaned_text = self.formatter.get_formatted_text()
103129

104130
# cleanup tmp file
105-
self.relase_resources(article)
131+
self.relase_resources()
106132

107-
return article
133+
# return the article
134+
return self.article
108135

109136
def get_parse_candidate(self, crawl_candidate):
110137
if crawl_candidate.raw_html:
111138
return RawHelper.get_parsing_candidate(crawl_candidate.url, crawl_candidate.raw_html)
112139
return URLHelper.get_parsing_candidate(crawl_candidate.url)
113140

141+
def get_image(self):
142+
doc = self.article.raw_doc
143+
top_node = self.article.top_node
144+
self.article.top_image = self.image_extractor.get_best_image(doc, top_node)
145+
114146
def get_html(self, crawl_candidate, parsing_candidate):
147+
# we got a raw_tml
148+
# no need to fetch remote content
115149
if crawl_candidate.raw_html:
116150
return crawl_candidate.raw_html
151+
117152
# fetch HTML
118-
html = HtmlFetcher().get_html(self.config, parsing_candidate.url)
153+
fetcher = HtmlFetcher(self.config, parsing_candidate.url)
154+
html = fetcher.get_html()
155+
#html = HtmlFetcher().get_html(self.config, parsing_candidate.url)
119156
return html
120157

121-
def get_image_extractor(self, article):
122-
http_client = None
123-
return UpgradedImageIExtractor(http_client, article, self.config)
158+
def get_image_extractor(self):
159+
return UpgradedImageIExtractor(self.config, self.article)
124160

125-
def get_video_extractor(self, article):
126-
return VideoExtractor(article, self.config)
161+
def get_video_extractor(self):
162+
return VideoExtractor(self.config, self.article)
127163

128-
def get_output_formatter(self):
129-
return StandardOutputFormatter(self.config)
164+
def get_formatter(self):
165+
return StandardOutputFormatter(self.config, self.article)
130166

131-
def get_document_cleaner(self):
132-
return StandardDocumentCleaner(self.config)
167+
def get_cleaner(self):
168+
return StandardDocumentCleaner(self.config, self.article)
133169

134170
def get_document(self, raw_html):
135171
doc = self.parser.fromstring(raw_html)
136172
return doc
137173

138174
def get_extractor(self):
139-
return StandardContentExtractor(self.config)
175+
return StandardContentExtractor(self.config, self.article)
140176

141-
def relase_resources(self, article):
142-
path = os.path.join(self.config.local_storage_path, '%s_*' % article.link_hash)
177+
def relase_resources(self):
178+
path = os.path.join(self.config.local_storage_path, '%s_*' % self.article.link_hash)
143179
for fname in glob.glob(path):
144180
try:
145181
os.remove(fname)

goose/extractors.py

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -43,32 +43,29 @@
4343

4444
class ContentExtractor(object):
4545

46-
def __init__(self, config):
46+
def __init__(self, config, article):
47+
# config
4748
self.config = config
49+
4850
# parser
4951
self.parser = self.config.get_parser()
52+
53+
# article
54+
self.article = article
55+
56+
# language
5057
self.language = config.target_language
58+
59+
# stopwords class
5160
self.stopwords_class = config.stopwords_class
5261

53-
def get_language(self, article):
54-
"""\
55-
Returns the language is by the article or
56-
the configuration language
57-
"""
58-
# we don't want to force the target laguage
59-
# so we use the article.meta_lang
60-
if self.config.use_meta_language == True:
61-
if article.meta_lang:
62-
self.language = article.meta_lang[:2]
63-
self.language = self.config.target_language
64-
65-
def get_title(self, article):
62+
def get_title(self):
6663
"""\
6764
Fetch the article title and analyze it
6865
"""
6966

7067
title = ''
71-
doc = article.doc
68+
doc = self.article.doc
7269

7370
title_element = self.parser.getElementsByTag(doc, tag='title')
7471
# no title found
@@ -121,34 +118,34 @@ def split_title(self, title, splitter):
121118
title = title_pieces[large_text_index]
122119
return TITLE_REPLACEMENTS.replaceAll(title).strip()
123120

124-
def get_favicon(self, article):
121+
def get_favicon(self):
125122
"""\
126123
Extract the favicon from a website
127124
http://en.wikipedia.org/wiki/Favicon
128125
<link rel="shortcut icon" type="image/png" href="favicon.png" />
129126
<link rel="icon" type="image/png" href="favicon.png" />
130127
"""
131128
kwargs = {'tag': 'link', 'attr': 'rel', 'value': 'icon'}
132-
meta = self.parser.getElementsByTag(article.doc, **kwargs)
129+
meta = self.parser.getElementsByTag(self.article.doc, **kwargs)
133130
if meta:
134131
favicon = self.parser.getAttribute(meta[0], 'href')
135132
return favicon
136133
return ''
137134

138-
def get_meta_lang(self, article):
135+
def get_meta_lang(self):
139136
"""\
140137
Extract content language from meta
141138
"""
142139
# we have a lang attribute in html
143-
attr = self.parser.getAttribute(article.doc, attr='lang')
140+
attr = self.parser.getAttribute(self.article.doc, attr='lang')
144141
if attr is None:
145142
# look up for a Content-Language in meta
146143
items = [
147144
{'tag': 'meta', 'attr': 'http-equiv', 'value': 'content-language'},
148145
{'tag': 'meta', 'attr': 'name', 'value': 'lang'}
149146
]
150147
for item in items:
151-
meta = self.parser.getElementsByTag(article.doc, **item)
148+
meta = self.parser.getElementsByTag(self.article.doc, **item)
152149
if meta:
153150
attr = self.parser.getAttribute(meta[0], attr='content')
154151
break
@@ -175,45 +172,45 @@ def get_meta_content(self, doc, metaName):
175172

176173
return ''
177174

178-
def get_meta_description(self, article):
175+
def get_meta_description(self):
179176
"""\
180177
if the article has meta description set in the source, use that
181178
"""
182-
return self.get_meta_content(article.doc, "meta[name=description]")
179+
return self.get_meta_content(self.article.doc, "meta[name=description]")
183180

184-
def get_meta_keywords(self, article):
181+
def get_meta_keywords(self):
185182
"""\
186183
if the article has meta keywords set in the source, use that
187184
"""
188-
return self.get_meta_content(article.doc, "meta[name=keywords]")
185+
return self.get_meta_content(self.article.doc, "meta[name=keywords]")
189186

190-
def get_canonical_link(self, article):
187+
def get_canonical_link(self):
191188
"""\
192189
if the article has meta canonical link set in the url
193190
"""
194-
if article.final_url:
191+
if self.article.final_url:
195192
kwargs = {'tag': 'link', 'attr': 'rel', 'value': 'canonical'}
196-
meta = self.parser.getElementsByTag(article.doc, **kwargs)
193+
meta = self.parser.getElementsByTag(self.article.doc, **kwargs)
197194
if meta is not None and len(meta) > 0:
198195
href = self.parser.getAttribute(meta[0], 'href')
199196
if href:
200197
href = href.strip()
201198
o = urlparse(href)
202199
if not o.hostname:
203-
z = urlparse(article.final_url)
200+
z = urlparse(self.article.final_url)
204201
domain = '%s://%s' % (z.scheme, z.hostname)
205202
href = urljoin(domain, href)
206203
return href
207-
return article.final_url
204+
return self.article.final_url
208205

209-
def get_domain(self, url):
210-
if url:
211-
o = urlparse(url)
206+
def get_domain(self):
207+
if self.article.final_url:
208+
o = urlparse(self.article.final_url)
212209
return o.hostname
213210
return None
214211

215-
def extract_tags(self, article):
216-
node = article.doc
212+
def extract_tags(self):
213+
node = self.article.doc
217214

218215
# node doesn't have chidren
219216
if len(list(node)) == 0:
@@ -233,8 +230,8 @@ def extract_tags(self, article):
233230

234231
return set(tags)
235232

236-
def calculate_best_node(self, article):
237-
doc = article.doc
233+
def calculate_best_node(self):
234+
doc = self.article.doc
238235
top_node = None
239236
nodes_to_check = self.nodes_to_check(doc)
240237

@@ -507,11 +504,12 @@ def is_nodescore_threshold_met(self, node, e):
507504
return False
508505
return True
509506

510-
def post_cleanup(self, targetNode):
507+
def post_cleanup(self):
511508
"""\
512509
remove any divs that looks like non-content,
513510
clusters of links, or paras with no gusto
514511
"""
512+
targetNode = self.article.top_node
515513
node = self.add_siblings(targetNode)
516514
for e in self.parser.getChildren(node):
517515
e_tag = self.parser.getTag(e)

goose/images/extractors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class ImageExtractor(object):
4949

5050
class UpgradedImageIExtractor(ImageExtractor):
5151

52-
def __init__(self, http_client, article, config):
52+
def __init__(self, config, article):
5353
self.custom_site_mapping = {}
5454
self.load_customesite_mapping()
5555

0 commit comments

Comments
 (0)