我正在尝试镜像一个网站的内容,不幸的是它的大部分是基于 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()吗?这可能会导致内存泄漏。
