Skip to main content
 首页 » 编程设计

Python, GTK, Webkit & scraping, 大内存问题

2025年05月04日40jillzhang

我正在尝试镜像一个网站的内容,不幸的是它的大部分是基于 javascript 的,包括生成 href 的代码。这消除了大多数标准的网络抓取工具(如 httrack),因为它们处理 javascript 的尝试,即使他们确实尝试过,也是非常不可靠的。

所以我决定自己用 python 编写并让 webkit 引擎处理 HTML。程序逻辑看起来非常简单,生成一个字典,其中找到的 url 作为键,根据它是否已经被处理,值为 0 或 1。我设法让基本逻辑与 pyqt4 一起工作得相当好,但它在随机时间保持段错误,足以让我不信任它,然后我发现了这个:http://blog.motane.lu/2009/06/18/pywebkitgtk-execute-javascript-from-python/

简洁的脚本,它可以工作,但我以前从未在 python 中处理过 gtk。虽然用我的逻辑来围绕它是相当简单的,但事实证明它有点占用内存。使用 meliae 对其进行分析显示没有占用那么多内存,即使 python 达到 2Gb。该网站有相当少的页面,脚本最终达到 32 位内存限制和段错误。我的假设是代码生成了越来越多的 webkit 窗口。我不知道如何让它真正关闭或销毁那些 window 。我试过销毁,那里有一个 main_quit,似乎没有什么可以关闭它。

这里应该是相关部分(我希望如此),但目标 url 已更改。我正在使用 url 和 foundurl 的字典,但切换到 anydbm 以防它们出于某种奇怪的原因占用内存。我可能会在某个时候切换回听写:

#!/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() 

请您参考如下方法:

我没有实际使用过WebKit,但是self.destroy不应该改成self.destroy()吗?这可能会导致内存泄漏。