【问题标题】:Unable to select the table data in scrapy无法在scrapy中选择表格数据
【发布时间】:2021-06-24 17:58:21
【问题描述】:

我正在尝试 scrape 这个website 用于学术目的,使用 css/xpath 选择器进行scrapy。

我需要在 ID 为DataTables_Table_0 的表格中选择td 中的详细信息。但是我什至无法选择包含表格的 div 元素,更不用说表格数据了。

我要解析的 HTML 块是

# please ignore wrong indentation
<div id="fund-selector-data">
    <div class=" ">
        <div id="DataTables_Table_0_wrapper" class="dataTables_wrapper no-footer">
            <div class="dataTables_scroll">
                <div class="dataTables_scrollHead"
                </div>
            <div class="dataTables_scrollBody" style="position: relative; overflow: auto; width: 100%;">
                  <table class="row-border dataTable table-snapshot no-footer" data-order="[]" cellspacing="0" width="100%"
        id="DataTables_Table_0" role="grid" style="width: 100%;">
                        <thead>
                        </thead>
        <tbody>
        <tr role="row" class="odd">
        <td><a href="/downloads/fund-card/38821" class="orange">PDF</a></td>
        <td class=" text-left"><a href="/funds/38821/aditya-birla-sun-life-bal-bhavishya-yojna-direct-plan">ABSL Bal
                Bhavishya Yojna Dir</a>&nbsp;|&nbsp;<a class="invest-online-blink invest-online " target="_blank"
                href="/funds/invest-online-tracking/420/" data-amc="aditya-birla-sun-life-mutual-fund"
                data-fund="aditya-birla-sun-life-bal-bhavishya-yojna-direct-plan">Invest Online</a></td>
        <td data-order="" class=" text-left">
            <div class="raterater-layer text-left test-fund-rating-star "><small>Unrated</small></div>
        </td>
        <td class=" text-left"><a
                href="/premium/?utm_medium=vro&amp;utm_campaign=premium-unlock&amp;utm_source=fund-selector">
                <div class="unlock-premium"></div>
            </a></td>
        </tbody>

scrapy CSS 选择器如下:

# Selecting Table (selector)
response.css("#DataTables_Table_0")         # returns blank list
# Selecting div class (selector)
response.css(".dataTables_scrollBody")      # returns blank list
# Selecting td element
response.css("#DataTables_Table_0 tbody tr td a::text").getall()        # returns blank list

我也尝试过 xpath 来选择元素,但得到了相同的结果。我发现我无法选择div 下方的任何元素,并且类为空。我无法理解为什么它在这种情况下不起作用?我错过了什么吗?任何帮助将不胜感激。

【问题讨论】:

    标签: python web-scraping xpath scrapy css-selectors


    【解决方案1】:

    问题

    看起来您尝试选择的元素是通过 javascript 作为单独的 API 调用加载的。如果您访问该页面,该表有消息:

    我们正在获取数据,请稍候...

    Scrapy 文档有一个section about this,他们的建议是找到动态加载内容的来源,并从您的爬取代码中模拟这些请求。

    解决方案

    可以通过查看 Chrome 开发工具中的 XHR 网络标签找到数据源。

    在这种情况下,您尝试解析的表的数据源似乎是

    https://www.valueresearchonline.com/funds/selector-data/primary-category/1/equity/?plan-type=direct&amp;tab=snapshot&amp;output=html-data

    这似乎是原始 URL 的副本,但将 selector 替换为 selector-data 并在末尾添加一个 output=html-data 查询参数。

    这将返回具有以下格式的 JSON 对象:

    {
        title: ...,
        tracking_url: ...,
        tools_title: ...,
        html_data: ...,
        recordsTotal: ...
    }
    

    看起来html_data 是您想要的字段,因为它包含您最初想要的动态表格html。您现在可以简单地加载这个html_data 并像以前一样解析它。

    为了在您的抓取代码中模拟所有这些,只需向您的蜘蛛添加一个parse_table 方法来处理上述 json 响应。您可能还想 根据您当前正在抓取的页面动态生成表格数据源 URL,因此值得添加一个添加编辑原始 URL 的方法,如上所述。

    示例代码

    我不确定您是如何设置爬虫的,因此我编写了一些方法,可以轻松移植到您当前使用的任何爬虫设置中。

    import json
    import scrapy
    from scrapy.http import Request
    from urllib.parse import urlparse, urlencode, parse_qsl
    
    class TableSpider(scrapy.Spider):
        name = 'tablespider'
        start_urls = ['https://www.valueresearchonline.com/funds/selector/primary-category/1/equity/?plan-type=direct&tab=snapshot']
    
        def _generate_table_endpoint(self, base_url):
            """Dyanmically generate the table data endpoint."""
            # Parse the base url
            parsed = urlparse(base_url)
            
            # Add output=html-data query param
            current_params = dict(parse_qsl(parsed.query))
            new_params = {'output': 'html-data'}
            merged_params = urlencode({**current_params, **new_params})
            
            # Update path to get selector data
            data_path = parsed.path.replace('selector', 'selector-data')
            
            # Update the URL with the new path and query params
            parsed = parsed._replace(path=data_path, query=merged_params)
            
            return parsed.geturl()
    
        def parse(self, response):
            # Any pre-request logic goes here
            # ...
            
            # Request and parse the table data source
            yield Request(
                self._generate_table_endpoint(response.url),
                callback=self.parse_table
            )
            
        def parse_table(self, response):
            try:
                # Load the json response into a dict
                res = json.loads(response.text)
                # Get the html_data value (containing the dynamic table html)
                table_html = res['html_data']
                
                # Your table data extraction goes here...
                # ===========================================================
                
            except:
                raise Exception('No table data present.')
            
            yield {'table_data': 'your response data'}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多