-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWeb_Crawler.py
More file actions
218 lines (182 loc) · 6 KB
/
Copy pathWeb_Crawler.py
File metadata and controls
218 lines (182 loc) · 6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
import bs4
import colorama
from random import randrange
import re
from random import randint
import requests
from requests.exceptions import SSLError, ReadTimeout, ConnectTimeout, ConnectionError
import sys
from urllib.parse import urljoin, urlsplit, urlunsplit
colorama.init() # only necessary in windows
OK = colorama.Fore.GREEN
ERROR = colorama.Fore.RED
BLUE = colorama.Fore.BLUE
BACKRED = colorama.Back.RED
RESET = colorama.Style.RESET_ALL
MAX_TOKEN_LEN = 15
CLEAN_RE = re.compile('\W+')
#######################
## WORKING WITH URLS ##
#######################
def get_site(url):
return urlsplit(url).netloc
###############################
## WORKING WITH HTML CONTENT ##
###############################
def download_web(url):
print('Getting "%s" ... ' % url, end='')
try:
r = requests.get(url, timeout=1)
print(OK + 'ok!' + RESET)
except (SSLError, ReadTimeout, ConnectTimeout, ConnectionError) as err:
print(ERROR + 'ERROR: %s' % err + RESET)
return None
return bs4.BeautifulSoup(r.text, 'lxml')#'html.parser')
def extract_urls(contenido, baseurl):
url_list = []
for link in contenido.find_all('a'):
newurl = link.get('href')
if newurl is None:
continue
full_new_url = urljoin(baseurl, newurl.strip())
surl = urlsplit(full_new_url)
if surl.scheme in ['http', 'https']:
ext = surl.path[surl.path.rfind('.'):].lower()
if ext not in [".pdf", ".jpg"]:
newurl = urlunsplit((surl.scheme, surl.netloc, surl.path, '', ''))
url_list.append(newurl)
return url_list
def extract_text(content):
return CLEAN_RE.sub(' ', content.text).lower()
############################
## WORKING WITH THE INDEX ##
############################
def add_processed_url(url_dic, url):
"""Add url to doc dictionary (url_dic)
Args:
url_dic: docs dictionary
url: url to add
Returns:
int: dictionary url key
"""
hs_url = hash(url)
url_dic[hs_url] = url
return (hs_url)
def get_next_url(url_queue):
"""Takes an url from the queue and it returns it
Args:
url_queue
Returns:
text: url
"""
url_data = url_queue.pop()
return url_data
def add_pending_url(url_queue, url, url_dic):
"""add url to the queue if there is no one here or in the dictionary
Args:
url_queue
url
url_dic: docs dictionary
Returns:
boolean: True if the url is correctly added. False if it already exist
"""
hs_url = hash(url)
aux = 1
for i in url_queue:
if i == url:
aux = 0
if aux:
try:
value = url_dic[hs_url]
return False
except KeyError:
url_queue.append(url)
return True
def add_to_index(index, urlid, text):
"""Add the appropiate docid of an url to the posting list of text's terms
Args:
index: inverted index
urlid: url's docid
text
Returns:
int: terms number processed
"""
local_count = 0
for word in text.split():
try:
old_data = [index[word]].append(urlid)
index[word] = set(old_data)
local_count += 1
except:
index[word] = [urlid]
local_count += 1
return local_count
def get_posting(index, dic, term):
"""Returns a list of url where the terms appears
Args:
index: inverted index
dic: docs dictionary, necessary to take the urls from de key(docid)
term
Returns:
list: list of url , None if the term does not exist in the inverted index
"""
final_list = []
try:
url_list = index[term]
except:
return []
for hs in url_list:
final_list.append(dic[hs])
return final_list
###############
## SHOW INFO ##
###############
def info(index, processed, pending):
print("\n====\nINFO\n====")
# about de index
print('Number of tokens:', len(index))
print('Number of processed urls:', len(processed))
if len(processed) != len(set(processed.values())):
print (BACKRED + "ERROR: SOME URLS ARE DUPLICATED" + RESET)
print('Number of pending urls:', len(pending))
print('-' * 50)
# searching words
words = ["computer", "enigma", "theory", "probability", "war",
"victory", "died"]
for word in words:
refs = get_posting(index, processed, word)
if refs is None:
print ("%s'%s'%s is not indexed" % (ERROR, word, RESET))
else:
print ("%s'%s'%s is in:" % (BLUE, word, RESET), ', '.join(sorted(refs)))
print('-' * 50)
# about the sites
l1 = sorted(set(get_site(url) for url in processed.values()))
l2 = sorted(set(get_site(url) for url in pending_urls).difference(l1))
max_len = max(len(s) for s in l1 + l2)
l1 = ([s.ljust(max_len) for s in l1])
l2 = ([s.ljust(max_len) for s in l2])
print('Processed Sites (%d):' % len(l1))
for i in range(int(len(l1)/4)+1):
print('\t'+'\t'.join(l1[i*4:i*4+4]))
print('-' * 50)
print('Pending Sites (%d):' % len(l2))
for i in range(int(len(l2)/4)+1):
print('\t'+'\t'.join(l2[i*4:i*4+4]))
if __name__ == "__main__":
MAX = int(sys.argv[1]) if len(sys.argv) > 1 else 10
inverted_index, processed_urls, pending_urls = {}, {}, []
add_pending_url(pending_urls, "https://es.wikipedia.org/wiki/Alan_Turing", processed_urls)
countGlobal = 0
for iter in range(MAX):
url = get_next_url(pending_urls)
print('(%d)' % iter, end=' ')
page = download_web(url)
if page is not None:
urlid = add_processed_url(processed_urls, url)
text = extract_text(page)
add_to_index(inverted_index, urlid, text)
url_list = extract_urls(page, url)
for new_url in url_list:
add_pending_url(pending_urls, new_url, processed_urls)
info(inverted_index, processed_urls, pending_urls)