Scrapy管理会话Cookie并支持完整的Webkit JavaScript执行

1 投票
2 回答
1197 浏览
提问于 2025-04-17 20:27

我正在尝试使用scrapy来抓取一个大量使用JavaScript来处理文档、cookies等的网站(但不是简单的像JSON响应那样)。出于某种原因,我无法从网络流量中确定,所需的页面在抓取时会出现错误,但在浏览器中查看时却没有。因此,我想用webkit来渲染这个页面,就像在浏览器中看到的一样,然后再进行抓取。scrapyjs项目就是为这个目的而创建的。

为了访问我需要的页面,我之前必须先登录,并保存了一些会话cookies。我的问题是,当webkit渲染页面时,我无法成功提供会话cookie。我想到两种方法来解决这个问题:

  1. 在到达需要webkit的页面之前,完全使用scrapy的页面请求,然后传递所需的cookies。
  2. 在整个会话中使用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 个回答

0

在不了解整个应用程序的工作流程的情况下,你需要确保在进行任何其他网络活动之前,先设置好“cookie jar”(就是存放cookie的地方)。根据我的经验,这意味着你甚至应该在创建网页视图之前就做好这一步。

另外一个需要检查的点是,你的框架(frames)是否来自同一个域名。因为cookie的政策不允许跨不同的域名使用cookie。

最后,你可能可以手动注入这些cookie。可以参考一下相关的链接,看看如何在实际的请求中设置cookie。

0

其实,第一种方法是可行的,不过需要做一个小改动。cookie的路径需要设置为'/'(至少在我的应用中是这样),而不是上面代码中的'None'。也就是说,这一行应该是

libsoup.soup_cookie_jar_add_cookie(cookiejar, libsoup.soup_cookie_new(cookiename,cookieval,up.hostname,'/',-1))

可惜的是,这样做只是把问题推迟了一点。现在cookie保存得不错了,但整个页面(包括框架)还是没有像我预期的那样用webkit加载和渲染,所以我在浏览器里看到的DOM结构并不完整。如果我只是请求我想要的框架,那我得到的却是错误页面,而不是在真实浏览器中显示的内容。我希望能知道如何用webkit渲染整个页面,包括框架。或者如何实现第二种方法,让整个会话在webkit中完成。

撰写回答