【发布时间】:2011-10-24 14:08:47
【问题描述】:
我正在尝试为网站镜像内容,不幸的是,其中大部分内容是基于 javascript 的,包括生成 href 的代码。这消灭了大多数标准的网络抓取工具(如 httrack),因为它们处理 javascript 的尝试,即使他们确实尝试过,也是非常不可靠的。
所以我决定用 python 编写自己的代码并让 webkit 引擎来处理 HTML。程序逻辑看起来很简单,生成一个 dict,其中 url 被找到作为键,值是 0 或 1,取决于它是否已经被处理。我设法让基本逻辑与 pyqt4 一起工作得相当好,但它总是随机出现段错误,足以让我不信任它,然后我发现了这个:http://blog.motane.lu/2009/06/18/pywebkitgtk-execute-javascript-from-python/
整洁的脚本,它可以工作,但我以前从未在 python 中处理过 gtk。不过,将我的逻辑固定在它周围是相当简单的,但事实证明它有点占用内存。使用 meliae 对其进行分析显示没有占用那么多内存,即使 python 达到 2Gb。该站点有相当多的页面,脚本最终达到 32 位内存限制和段错误。我的假设是代码正在产生越来越多的 webkit 窗口。我不知道如何让它真正关闭或摧毁那些窗户。我试过destroy,里面有一个main_quit,好像没有关闭它。
这应该是相关部分(我希望),但目标网址已更改。我对 url 和 foundurl 使用 dicts 但切换到 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()
【问题讨论】: