Scrapy管理会话Cookie并支持完整的Webkit JavaScript执行
我正在尝试使用scrapy来抓取一个大量使用JavaScript来处理文档、cookies等的网站(但不是简单的像JSON响应那样)。出于某种原因,我无法从网络流量中确定,所需的页面在抓取时会出现错误,但在浏览器中查看时却没有。因此,我想用webkit来渲染这个页面,就像在浏览器中看到的一样,然后再进行抓取。scrapyjs项目就是为这个目的而创建的。
为了访问我需要的页面,我之前必须先登录,并保存了一些会话cookies。我的问题是,当webkit渲染页面时,我无法成功提供会话cookie。我想到两种方法来解决这个问题:
- 在到达需要webkit的页面之前,完全使用scrapy的页面请求,然后传递所需的cookies。
- 在整个会话中使用webkit(通过修改版的scrapyjs),从登录开始直到我到达需要的页面,并允许它根据需要保存cookies。
不幸的是,这两种方法似乎都没有成功。
关于第一种方法,我尝试了以下操作: 在settings.py中 --
DOWNLOADER_MIDDLEWARES = {
'scrapyjs.middleware.WebkitDownloader': 701, #to run after CookiesMiddleware
}
我修改了scrapyjs以发送cookies: scrapyjs/middleware.py--
import gtk
import webkit
import jswebkit
#import gi.repository import Soup # conflicting static and dynamic includes!?
import ctypes
libsoup = ctypes.CDLL('/usr/lib/i386-linux-gnu/libsoup-2.4.so.1')
libwebkit = ctypes.CDLL('/usr/lib/libwebkitgtk-1.0.so.0')
def process_request( self, request, spider ):
if 'renderjs' in request.meta:
cookies = request.headers.getlist('Cookie')
if len(cookies)>0:
cookies = cookies[0].split('; ')
cookiejar = libsoup.soup_cookie_jar_new()
libsoup.soup_cookie_jar_set_accept_policy(cookiejar,0) #0==ALWAYS ACCEPT
up = urlparse(request.url)
for c in cookies:
sp=c.find('=') # find FIRST = as split position
cookiename = c[0:sp]; cookieval = c[sp+1:];
libsoup.soup_cookie_jar_add_cookie(cookiejar, libsoup.soup_cookie_new(cookiename,cookieval,up.hostname,'None',-1))
session = libwebkit.webkit_get_default_session()
libsoup.soup_session_add_feature(session,cookiejar)
webview = self._get_webview()
webview.connect('load-finished', self.stop_gtk)
webview.load_uri(request.url)
...
设置cookiejar的代码是参考了这个回答。问题可能出在导入的方式上;也许我修改的不是正确的webkit——我对webkit不太熟悉,Python的文档也不太好。(我不能使用第二个答案中的方法from gi.repository import Soup
,因为它混合了静态和动态库。我也找不到在上面导入的webkit中有get_default_session())。
第二种方法失败是因为会话在请求之间没有被保存,而且我对webkit了解不够,不知道如何在这个框架中让它持久化。
任何帮助都非常感谢!
2 个回答
在不了解整个应用程序的工作流程的情况下,你需要确保在进行任何其他网络活动之前,先设置好“cookie jar”(就是存放cookie的地方)。根据我的经验,这意味着你甚至应该在创建网页视图之前就做好这一步。
另外一个需要检查的点是,你的框架(frames)是否来自同一个域名。因为cookie的政策不允许跨不同的域名使用cookie。
最后,你可能可以手动注入这些cookie。可以参考一下相关的链接,看看如何在实际的请求中设置cookie。
其实,第一种方法是可行的,不过需要做一个小改动。cookie的路径需要设置为'/'(至少在我的应用中是这样),而不是上面代码中的'None'。也就是说,这一行应该是
libsoup.soup_cookie_jar_add_cookie(cookiejar, libsoup.soup_cookie_new(cookiename,cookieval,up.hostname,'/',-1))
可惜的是,这样做只是把问题推迟了一点。现在cookie保存得不错了,但整个页面(包括框架)还是没有像我预期的那样用webkit加载和渲染,所以我在浏览器里看到的DOM结构并不完整。如果我只是请求我想要的框架,那我得到的却是错误页面,而不是在真实浏览器中显示的内容。我希望能知道如何用webkit渲染整个页面,包括框架。或者如何实现第二种方法,让整个会话在webkit中完成。