Python strategy for extracting text from malformed html pages

html, html-content-extraction, python, text

Solution

Try not to laugh, but:

class TextFormatter:
    def __init__(self,lynx='/usr/bin/lynx'):
        self.lynx = lynx

    def html2text(self, unicode_html_source):
        "Expects unicode; returns unicode"
        return Popen([self.lynx, 
                      '-assume-charset=UTF-8', 
                      '-display-charset=UTF-8', 
                      '-dump', 
                      '-stdin'], 
                      stdin=PIPE, 
                      stdout=PIPE).communicate(input=unicode_html_source.encode('utf-8'))[0].decode('utf-8')

I hope you've got lynx!

Problem

I'm trying to extract text from arbitrary html pages. Some of the pages (which I have no control over) have malformed html or scripts which make this difficult. Also I'm on a shared hosting environment, so I can install any python lib, but I can't just install anything I want on the server. pyparsing and html2text.py also did not seem to work for malformed html pages. Example URL is http://apnews.myway.com/article/20091015/D9BB7CGG1.html My current implementation is approximately the following: ``` # Try using BeautifulSoup 3.0.7a soup = BeautifulSoup.BeautifulSoup(s) comments = soup.findAll(text=lambda text:isinstance(text,Comment)) [comment.extract() for comment in comments] c=soup.findAll('script') for i in c: i.extract() body = bsoup.body(text=True) text = ''.join(body) # if BeautifulSoup can't handle it, # alter html by trying to find 1st instance of "<body" and replace everything prior to that, with "<html><head></head>" # try beautifulsoup again with new html ``` if beautifulsoup still does not work, then I resort to using a heuristic of looking at the 1st char, last char (to see if they looks like its a code line # < ; and taking a sample of the line and then check if the tokens are english words, or numbers. If to few of the tokens are words or numbers, then I guess that the line is code. I could use machine learning to inspect each line, but that seems a little expensive and I would probably have to train it (since I don't know that much about unsupervised learning machines), and of course write it as well. Any advice, tools, strategies would be most welcome. Also I realize that the latter part of that is rather messy since if I get a line that is determine to contain code, I currently throw away the entire line, even if there is some small amount of actual English text in the line.

Original source