使用Scrapy和Python从JavaScript抓取数据

2 投票
1 回答
2109 浏览
提问于 2025-04-18 08:16

我想从cbfcindia网站上抓取所有电影的数据。

1) 在搜索框中,如果标题输入为"a",那么所有以"a"开头的电影都会显示出来(在网址中,参数是va=a&Type=search)。 http://cbfcindia.gov.in/html/uniquepage.aspx?va=a&Type=search

2) 这些电影会以表格的形式列出来,现在这里涉及到JavaScript,如果我点击第一部电影,我就能看到它的详细信息,我希望能抓取所有电影的这些详细信息。 但是我连一部电影的信息都抓取不了。

3) 我的观察是:在源代码中有以下函数:

function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}

我们需要根据JavaScript传递参数。但我不知道该怎么做。

items.py

from scrapy.item import Item, Field

class CbfcItem(Item):
    MovieName = Field()
    MovieLanguage = Field()
    Roffice = Field()
    CertificateNo = Field()
    CertificateDate = Field()
    Length = Field()
    NameofProducer = Field()
    #pass

cbfcspider.py

from cbfc.items import CbfcItem

class MySpider(BaseSpider):
    name = 'cbfc'
    allowed_domains= ["http://cbfcindia.gov.in/"]
    start_urls = ["http://cbfcindia.gov.in/html/uniquepage.aspx?va=a&Type=search"]

    def parse(self, response):
        hxs = HtmlXPathSelector(response)
        titles = hxs.select("//tbody")    #Check
        print titles
        items = []
        for titles in titles:
            print "in FOR loop"
            item = CbfcItem()
            item ["MovieName"] = hxs.path('//*[@id="lblMovieName"]/text()').extract()
            item ["MovieLanguage"] = hxs.path('//*[@id="lblLanguage"]').extract()
            item ["Roffice"] = hxs.path('//*[@id="lblRegion"]').extract()
            item ["CertificateNo"] = hxs.path('//*[@id="lblCertNo"]').extract()
            item ["CertificateDate"] = hxs.path('//*[@id="Label1"]').extract()
            item ["Length"] = hxs.path('//*[@id="lblCertificateLength"]').extract()
            item ["NameofProducer"] = hxs.path('//*[@id="lblProducer"]').extract()
            items.append(item)          
            print "this is ITEMS"
        return items
        print "End of FOR"

1 个回答

2

如果你仔细看看源代码,每个链接都有以下的标记:

<a id="DGMovie_ctl03_lnk" href="javascript:__doPostBack('DGMovie$ctl03$lnk','')">AGNI PARIKSHAYA</a>

现在你知道这个JavaScript函数是怎么被调用的了,你也知道了事件目标和事件参数的值。为了确保你走在正确的路上,你可以使用开发者工具来检查发生了什么。如果你用的是Chrome浏览器,记得勾选“保留日志”按钮。你会在href中看到第一个传回的参数是EVENTTARGET。

使用带有正则表达式的xpath可以获取所有的传回参数:

sel.xpath("//*[contains(@id,'DGMovie')]/@href").re("doPostBack\(\'([^']+)")

你需要用每个参数发送POST请求才能获取信息。注意你的网页使用了iframe,所以你需要先进入iframe的源代码。

pawel@stack:~/stack$ scrapy shell "http://cbfcindia.gov.in/html/uniquepage.aspx?va=a&Type=search"
In [31]: url = sel.xpath("//iframe/@src").extract()[0]

In [33]: url
Out[33]: u'searchresults.aspx?va=a&Type=search'

In [35]: from urlparse import urljoin

In [36]: url = urljoin(response.url, url) 

In [39]: from scrapy.http import Request

In [40]: req = Request(url)
in [41]: fetch(req)

# after fetching request..
In [48]: js_links = sel.xpath("//*[contains(@id,'DGMovie')]/@href").re("doPostBack\(\'([^']+)")
In [49]: param = js_links[0]

In [50]: param
Out[50]: u'DGMovie$ctl03$lnk'

In [51]: from scrapy.http import FormRequest

In [52]: fr = FormRequest.from_response(response, formdata={"__EVENTTARGET":param})

In [53]: fetch(fr)
2014-06-02 21:09:09+0100 [default] DEBUG: Redirecting (302) to <GET http://cbfcindia.gov.in/html/SearchDetails.aspx?mid=15&Loc=Backlog> from <POST http://cbfcindia.gov.in/html/searchresults.aspx?va=a&Type=search>
2014-06-02 21:09:10+0100 [default] DEBUG: Crawled (200) <GET http://cbfcindia.gov.in/html/SearchDetails.aspx?mid=15&Loc=Backlog> (referer: None)
In [54]: view(response)

在爬虫中,你需要重构你的解析方法,使其返回FormRequest,并设置回调函数为parse_items,然后把你的解析逻辑移到parse_items中(从parse中移过来)。

别忘了分页,这也是通过传回参数来实现的!

那些带有传回参数的asp.net页面通常是最难解析的。如果你感兴趣,可以阅读更多相关内容

撰写回答