| @@ -54,12 +54,16 @@ class CopyvioMixIn(object): | |||||
| self._opener.addheaders = site._opener.addheaders | self._opener.addheaders = site._opener.addheaders | ||||
| def _open_url_ignoring_errors(self, url): | def _open_url_ignoring_errors(self, url): | ||||
| """Open a URL using self._opener and return its content, or None. | |||||
| """Open a URL and return its parsed content, or None. | |||||
| Will decompress the content if the headers contain "gzip" as its | |||||
| content encoding, and will return None if URLError is raised while | |||||
| opening the URL. IOErrors while gunzipping a compressed response are | |||||
| ignored, and the original content is returned. | |||||
| First, we will decompress the content if the headers contain "gzip" as | |||||
| its content encoding. Then, we will return the content stripped using | |||||
| an HTML parser if the headers indicate it is HTML, or return the | |||||
| content directly if it is plain text. If we don't understand the | |||||
| content type, we'll return None. | |||||
| If a URLError was raised while opening the URL or an IOError was raised | |||||
| while decompressing, None will be returned. | |||||
| """ | """ | ||||
| try: | try: | ||||
| response = self._opener.open(url.encode("utf8"), timeout=5) | response = self._opener.open(url.encode("utf8"), timeout=5) | ||||
| @@ -73,9 +77,16 @@ class CopyvioMixIn(object): | |||||
| try: | try: | ||||
| result = gzipper.read() | result = gzipper.read() | ||||
| except IOError: | except IOError: | ||||
| pass | |||||
| return result | |||||
| return None | |||||
| ctype_full = response.headers.get("Content-Type", "text/plain") | |||||
| ctype = ctype_full.split(" ", 1)[0] | |||||
| if ctype in ["text/html", "application/xhtml+xml"]: | |||||
| return HTMLTextParser(result).strip() | |||||
| elif ctype == "text/plain": | |||||
| return result.strip() | |||||
| else: | |||||
| return None | |||||
| def _select_search_engine(self): | def _select_search_engine(self): | ||||
| """Return a function that can be called to do web searches. | """Return a function that can be called to do web searches. | ||||
| @@ -108,12 +119,12 @@ class CopyvioMixIn(object): | |||||
| The *article* is a Markov chain, whereas the *url* is just a string | The *article* is a Markov chain, whereas the *url* is just a string | ||||
| that we'll try to open and read ourselves. | that we'll try to open and read ourselves. | ||||
| """ | """ | ||||
| html = self._open_url_ignoring_errors(url) | |||||
| if not html: | |||||
| text = self._open_url_ignoring_errors(url) | |||||
| if not text: | |||||
| empty = MarkovChain("") | empty = MarkovChain("") | ||||
| return 0, (empty, MarkovChainIntersection(empty, empty)) | return 0, (empty, MarkovChainIntersection(empty, empty)) | ||||
| source = MarkovChain(HTMLTextParser(html).strip()) | |||||
| source = MarkovChain(text) | |||||
| delta = MarkovChainIntersection(article, source) | delta = MarkovChainIntersection(article, source) | ||||
| return float(delta.size()) / article.size(), (source, delta) | return float(delta.size()) / article.size(), (source, delta) | ||||