使用scrapy抓取动态网页的数据

时间:2014-07-12 04:24:36

标签: javascript python scrapy web-crawler

我正试图从NBA的官方统计数据中获取一些数据用于某些数据分析。我用scrapy作为刮擦的主要工具。但是,在检查网页元素后,我发现它是使用javascript动态生成的。我是javascript的新手,无法弄清楚它是如何工作的。(调用哪个js文件,如何加载包含数据表以及是否有更容易访问的方式来获取数据)我也有在网络中找到了一些json文件,我不知道如何使用它。

http://stats.nba.com/teamLineups.html?TeamID=1610612739&pageNo=1&rowsPerPage=100&Season=2008-09&sortField=MIN&sortOrder=DES&PerMode=Per48

任何人都可以指导我使用上面的网址告诉我网站如何实际运作以加载数据以及他们如何处理数据以便以这种方式显示?

关键部分仍然是如何获取数据。我已经看到了使用POST方法来获取数据的答案(对不起,我甚至不熟悉GET / POST)但我仍然无法弄清楚这是如何适用于这种情况的。

感谢您的慷慨指导!

3 个答案:

答案 0 :(得分:4)

在此示例中,Javascript仅允许在网页上发送,接收和显示内容,而无需为每个请求实际重新加载网页。 所以你不需要解析javascript,你只需要找到所请求的信息,然后模仿该请求,并解析响应。为此,您可以在Firefox中使用Firebug,或在Chrome中使用开发工具(在Windows中使用ctrl + shift + J,在Mac中使用cmd + opt + J)。 在Chrome中,只需点击“网络”标签,您就会在点击网站时看到请求和回复。

在这个特定的例子中,当你想获得克利夫兰团队“2008-09”的统计数据时,javascript会发送多个请求。 您可能感兴趣的阵容请求是这样的: http://stats.nba.com/stats/teamdashlineups?PlusMinus=N&pageNo=1&GroupQuantity=5&TeamID=1610612739&GameID=&Location=&SeasonType=Regular+Season&Season=2008-09&PaceAdjust=N&DateFrom=&sortOrder=DES&VsConference=&OpponentTeamID=0&DateTo=&GameSegment=&LastNGames=0&VsDivision=&LeagueID=00&Outcome=&GameScope=&MeasureType=Base&PerMode=Per48&sortField=MIN&SeasonSegment=&Period=0&Rank=N&Month=0&rowsPerPage=100

这是scrapy base spider的一个例子。您只需要定义LineupItem,然后就可以使用scrapy crawl stats -o output.json执行它。

import json
from scrapy.spider import Spider
from scrapy.http import Request
from nba.items import LineupItem
from urllib import urlencode


class StatsSpider(Spider):
    name = "stats"
    allowed_domains = ["stats.nba.com"]
    start_urls = (
        'http://stats.nba.com/',
        )

    def parse(self, response):
        return self.get_lineup('1610612739','2008-09')

    def get_lineup(self, team_id, season):
        params = {
            'Season':         season,
            'SeasonType':     'Regular Season',
            'LeagueID':       '00',
            'TeamID':         team_id,
            'MeasureType':    'Base',
            'PerMode':        'Per48',
            'PlusMinus':      'N',
            'PaceAdjust':     'N',
            'Rank':           'N',
            'Outcome':        '',
            'Location':       '',
            'Month':          '0',
            'SeasonSegment':  '',
            'DateFrom':       '',
            'DateTo':         '',
            'OpponentTeamID': '0',
            'VsConference':   '',
            'VsDivision':     '',
            'GameSegment':    '',
            'Period':         '0',
            'LastNGames':     '0',
            'GroupQuantity':  '5',
            'GameScope':      '',
            'GameID':         '',
            'pageNo':         '1',
            'rowsPerPage':    '100',
            'sortField':      'MIN',
            'sortOrder':      'DES'
        }
        return Request(
            url="http://stats.nba.com/stats/teamdashlineups?" + urlencode(params),
            dont_filter=True,
            callback=self.parse_lineup
        )

    def parse_lineup(self,response):
        data = json.loads(response.body)
        for lineup in data['resultSets'][1]['rowSet']:
            item = LineupItem()
            item['group_set'] = lineup[0]
            item['group_id'] = lineup[1]
            item['group_name'] = lineup[2]
            item['gp'] = lineup[3]
            item['w'] = lineup[4]
            item['l'] = lineup[5]
            item['w_pct'] = lineup[6]
            item['min'] = lineup[7]
            item['fgm'] = lineup[8]
            item['fga'] = lineup[9]
            item['fg_pct'] = lineup[10]
            item['fg3m'] = lineup[11]
            item['fg3a'] = lineup[12]
            item['fg3_pct'] = lineup[13]
            item['ftm'] = lineup[14]
            item['fta'] = lineup[15]
            item['ft_pct'] = lineup[16]
            item['oreb'] = lineup[17]
            item['dreb'] = lineup[18]
            item['reb'] = lineup[19]
            item['ast'] = lineup[20]
            item['tov'] = lineup[21]
            item['stl'] = lineup[22]
            item['blk'] = lineup[23]
            item['blka'] = lineup[24]
            item['pf'] = lineup[25]
            item['pfd'] = lineup[26]
            item['pts'] = lineup[27]
            item['plus_minus'] = lineup[28]
            yield item

将导致json记录如下:

{"gp": 30, "fg_pct": 0.491, "group_name": "Ilgauskas,Zydrunas - James,LeBron - Wallace,Ben - West,Delonte - Williams,Mo", "group_set": "Lineups", "w_pct": 0.833, "pts": 103.0, "min": 484.9866666666667, "tov": 13.3, "fta": 21.6, "pf": 16.0, "blk": 7.7, "reb": 44.2, "blka": 3.0, "ftm": 16.6, "ft_pct": 0.771, "fg3a": 18.7, "pfd": 17.2, "ast": 23.3, "fg3m": 7.4, "fgm": 39.5, "fg3_pct": 0.397, "dreb": 32.0, "fga": 80.4, "plus_minus": 18.4, "stl": 8.3, "l": 5, "oreb": 12.3, "w": 25, "group_id": "980 - 2544 - 1112 - 2753 - 2590"}

答案 1 :(得分:1)

Scrapy无法运行javascript,因此您必须分析javascript代码并在Python和Scrapy中执行类似操作,或者识别javascript如何从服务器获取数据(使用哪些网址和参数)并将其用于您的脚本。这可能是很多工作 - 首先在Firefox中使用Firebug,然后使用Python和Scrapy。

如果您不知道如何做到这一点,那就更好地使用模拟真实浏览器并运行javascript的Selenium(或类似的东西)。您只需要向Selenium说明页面上的哪个按钮,表格中的文字等等。


import requests
import json

# set request as GET
response = requests.get('http://stats.nba.com/stats/teamdashlineups?Season=2008-09&SeasonType=Regular+Season&LeagueID=00&TeamID=1610612739&MeasureType=Base&PerMode=Per48&PlusMinus=N&PaceAdjust=N&Rank=N&Outcome=&Location=&Month=0&SeasonSegment=&DateFrom=&DateTo=&OpponentTeamID=0&VsConference=&VsDivision=&GameSegment=&Period=0&LastNGames=0&GroupQuantity=5&GameScope=&GameID=&pageNo=1&rowsPerPage=100&sortField=MIN&sortOrder=DES')

# change json into dictionary
data =  json.loads(response.text)

#print data

import pprint

pprint.pprint(data)

for x in data['resultSets']:
    print x['rowSet']

答案 2 :(得分:0)

我可能无法按照您想要的细节回答您的问题,但这是我理解的方式。

当您转到某个页面时,浏览器GET是该页面的源代码,与您在点击"查看页面来源"时看到的源代码相同。在铬。浏览器解释代码以及何时找到" src"指向外部文件的属性,它将该文件导入源,再次使用GET请求。

<script src="/js/libs/modernizr.custom.16166.js"></script>

导入JavaScript文件后,可以自行运行

jsfile.js:

function myFunction() {
//
//do stuff
//
}

myFunction();

对于您的nba站点,导入的文件会创建表并使用ajax GET请求填充该表。

您的nba网站似乎使用来自&#34; jquery.statrequest.js&#34;的#ajax GET请求从此link获取表信息。和&#34; team-lineups.js&#34;,它一团糟,所以你可能仍然想要正常刮取页面。

如果你决定刮掉页面,你将无法使用urllib,因为它只是获取页面源,它​​不会导入任何外部.js脚本,也不会运行JavaScript代码,在这种情况下,页面上的表格不会被创建并填充nba统计信息。

您需要使用类似Mechanize的内容,它会模拟浏览器并导入并运行JavaScript。

我希望这可以让你知道你想知道什么,我对浏览器的内部运作并不熟悉。你可能想找一个网站,它有免费的API用于nda游戏统计数据。

以下是来自nba网站的其他link,可能与您相关。