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

Javascript 使用scrapy抓取动态网页中的数据,javascript,python,scrapy,web-crawler,Javascript,Python,Scrapy,Web Crawler,我正试图从NBA官方统计数据中获取一些数据,用于数据分析。我使用刮削作为我的主要工具刮削。然而,在检查网页元素之后,我发现它是使用javascript动态生成的。我对javascript完全陌生,无法弄清楚它到底是如何工作的(调用了哪个js文件,它是如何加载到哪个包含数据表中的,以及是否有更容易访问的方式来获取数据),我还在网络中找到了一些json文件,我不知道它是如何使用的 有谁能好心地指导我使用上面的url,并告诉我网站如何实际运行以加载数据,以及他们如何处理数据以这种方式显示 关键部分仍

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

有谁能好心地指导我使用上面的url,并告诉我网站如何实际运行以加载数据,以及他们如何处理数据以这种方式显示

关键部分仍然是如何获取数据。我看到过使用POST方法来获取数据的答案(很抱歉,我甚至不熟悉get/POST),但我仍然不知道这如何适用于这种情况


感谢您的慷慨指导

Scrapy无法运行javascript,所以您必须分析javascript代码,并在Python和Scrapy中执行类似的操作,或者识别javascript如何从服务器获取数据(它使用的URL和参数)并将其用于您的脚本。这可能需要大量的工作——首先是Firefox中的Firebug,然后是Python和Scrapy

如果您不知道如何做到这一点,最好使用模拟真实浏览器并可以运行javascript的
Selenium
(或类似的东西)。您只需告诉Selenium,页面上按了哪个按钮,表单中放了什么文本,等等



我可能无法详细回答您的问题,但以下是我的理解

当你进入一个页面时,浏览器
会获取该页面的源代码,与你在chrome中单击“查看页面源代码”时看到的源代码相同。浏览器解释代码,如果找到指向外部文件的“src”属性,它会再次通过
GET
请求将该文件导入源文件

<script src="/js/libs/modernizr.custom.16166.js"></script>
对于nba站点,导入的文件将创建表,并用ajax
GET
请求填充它

您的nba网站似乎使用来自“jquery.statrequest.js”和“team lineups.js”的ajax
get
请求从中获取表格信息,这是一个混乱,因此您可能仍然希望正常地刮取页面

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

您需要使用类似的东西,它模拟浏览器并导入和运行JavaScript

我希望这能让你对你想知道的有所了解,我对浏览器的内部工作原理不太熟悉。你可能想找一个网站,有免费的API的nda游戏统计


以下是nba网站上的另一个可能与您相关的内容。

在本例中,Javascript只允许在网页上发送、接收和显示内容,而无需为每个请求重新加载网页。 因此,您不需要解析javascript,只需找到所请求的信息,然后模拟该请求并解析响应。为此,您可以在Firefox中使用Firebug,也可以在Chrome中使用开发工具(windows中使用ctrl+shift+J,Mac中使用cmd+opt+J)。 在Chrome中,只需单击“网络”选项卡,当您在网站中单击时,您将看到请求和响应

在这个特定的示例中,当您想要获取克利夫兰团队“2008-09”的统计数据时,javascript会发送多个请求。 您可能感兴趣的阵容请求如下:

这是一个刮痧蜘蛛的例子。您只需要定义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"}

实际上,我以前做过的是,我尝试在python中使用json加载数据,然后我想将其读入pandas中的数据框中,但格式不正确。您可以尝试更改url中的参数以获取其他数据-例如,您可以更改年份。可以使用module
PrettyPrint
(请参阅上面的代码)为了更好地查看数据。可能字典(子字典)的一部分可以在
pandas
中使用,我找不到如此详细的解释!请注意,您是否可以解释有关回调函数的更多信息,以及为什么没有像scrapy中那样的解析函数。辅导的对那部分很困惑抱歉不清楚。。为什么解析函数不使用传入的响应?因为我不需要stats.nba.com页面上的任何内容,而且我不想将一个巨大的丑陋请求作为起始URL。因此,我在第一个请求上拍摄空白,然后实现一个函数,以获得给定球队和给定赛季的前100个阵容。要实际使用它,您需要实现一个爬行逻辑,该逻辑将向包含您想要的所有团队和季节的函数发出请求。
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
{"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"}