Python, GTK, Webkit & scraping, большая проблема с памятью - PullRequest
2 голосов
/ 11 августа 2011

Я пытаюсь зеркально отразить сайт на контенте, к сожалению, большая его часть основана на javascript, включая код, который генерирует hrefs.Это уничтожает большинство стандартных инструментов для очистки веб-страниц (таких как httrack), поскольку их попытки обработки javascript, даже если они и пытаются это сделать, крайне ненадежны.

Поэтому я решил написать свой собственный на python и получить движок webkitобрабатывать HTML.Процедурная логика кажется довольно простой: генерируйте dict с URL-адресами, найденными в качестве ключа, и значением, равным 0 или 1, в зависимости от того, было ли оно уже обработано.Мне удалось заставить базовую логику работать достаточно хорошо с pyqt4, но она продолжала работать с ошибками в случайное время, достаточно, чтобы заставить меня не доверять ей, и затем я нашел это: http://blog.motane.lu/2009/06/18/pywebkitgtk-execute-javascript-from-python/

Аккуратный скрипт, он работает, ноЯ никогда раньше не имел дело с gtk в python.Разобраться в моей логике было довольно просто, однако оказалось, что это что-то вроде памяти.Профилирование с помощью meliae показывает, что ничто не занимает столько памяти, даже когда python достигает 2 Гб.На сайте довольно много страниц, и сценарий в конечном итоге достигает 32-битного лимита памяти и сегментов.Я предполагаю, что код порождает все больше и больше окон WebKit.Я в недоумении, как заставить его закрыть или уничтожить эти окна.Я пытался уничтожить, там есть main_quit, кажется, ничто его не закрывает.

Вот то, что должно быть соответствующими частями (я надеюсь), но с измененным URL назначения.Я использовал dicts для url и foundurl, но переключился на anydbm на тот случай, если они по какой-то причудливой причине стали бродить по памяти.Возможно, в какой-то момент я снова переключусь на dicts:

#!/usr/bin/env python
import sys, thread
import gtk
import webkit
import warnings
from time import sleep
from BeautifulSoup import BeautifulSoup
import re
import os
import anydbm
import copy
from meliae import scanner

warnings.filterwarnings('ignore')

class WebView(webkit.WebView):
    def get_html(self):
        self.execute_script('oldtitle=document.title;document.title=document.documentElement.innerHTML;')
        html = self.get_main_frame().get_title()
        self.execute_script('document.title=oldtitle;')
        self.destroy
        return html

class Crawler(gtk.Window):
    def __init__(self, url, file):
        gtk.gdk.threads_init() # suggested by Nicholas Herriot for Ubuntu Koala
        gtk.Window.__init__(self)
        self._url = url
        self._file = file
        self.connect("destroy",gtk.main_quit)

    def crawl(self):
        view = WebView()
        view.open(self._url)
        view.connect('load-finished', self._finished_loading)
        self.add(view)
        gtk.main()
        return view.get_html()

    def _finished_loading(self, view, frame):
        with open(self._file, 'w') as f:
            f.write(view.get_html())
        gtk.main_quit()

.. Различные подпрограммы, которые просто обрабатывают конец BeautifulSoup, обрабатывают страницы, вытаскивают ссылки, приводят их в порядок и т. Д ...

def main():
    urls=anydbm.open('./urls','n')
    domain = "stackoverflow.com"
    baseUrl = 'http://'+domain
    urls['/']='0'
    while (check_done(urls) == 0):
        count = 0
        foundurls=anydbm.open('./foundurls','n')
        for url, done in urls.iteritems():
            if done == 1: continue
            print "Processing",url
            urls[str(url)] = '1'
            if (re.search(".*\/$",url)):
                outfile=domain+url+"index.html"
            elif (os.path.isdir(os.path.dirname(os.path.abspath(outfile)))):
                outfile=domain+url+"index.html"
            else:
                outfile=domain+url
            if not os.path.exists(os.path.dirname(os.path.abspath(outfile))):
                os.makedirs(os.path.dirname(os.path.abspath(outfile)))
            crawler = Crawler(baseUrl+url, outfile)
            html=crawler.crawl()
            soup = BeautifulSoup(html.__str__())
            for link in hrefs(soup,baseUrl):
                if not foundurls.has_key(str(link)):
                    foundurls[str(link)] = '0'
            del(html)   #  this is an attempt to get the object to vanish, tried del(Crawler) to no avail
            if count==5:
                scanner.dump_all_objects( 'filename' )
                count = 0
            else:
                count=count+1
        for url, done in foundurls.iteritems():
            if not urls.has_key(str(url)):
                urls[str(url)]='0'
        foundurls.close()
        os.remove('./foundurls')
    urls.close()
    os.remove('./urls')

if __name__ == '__main__':
    main()

1 Ответ

1 голос
/ 11 августа 2011

Я на самом деле не использовал WebKit, но не следует ли поменять self.destroy на self.destroy()?Это может быть причиной утечки памяти.

...