我可以从 highcharts.js 中抓取原始数据吗? [英] Can I scrape the raw data from highcharts.js?

查看:18
本文介绍了我可以从 highcharts.js 中抓取原始数据吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从使用 highcharts.js 显示图表的页面中抓取数据,因此我完成了对所有页面的解析以到达 下一页.然而,显示数据集的最后一页使用 highcharts.js 来显示图表,这似乎几乎不可能访问原始数据.

我使用 Python 3.5 和 BeautifulSoup.

还能解析吗?如果是这样,我该如何刮掉它?

解决方案

数据在脚本标签中.您可以使用 bs4 和正则表达式获取脚本标签.您也可以使用正则表达式提取数据,但我喜欢使用 /js2xml 将 js 函数解析为 xml 树:

from bs4 import BeautifulSoup进口请求进口重新导入 js2xml汤 = BeautifulSoup(requests.get("http://www.worldweatheronline.com/brussels-weather-averages/be.aspx").content, "html.parser")脚本 = 汤.find("脚本", text=re.compile("Highcharts.Chart")).text# script = soup.find("script", text=re.compile("precipchartcontainer")).text 如果你想要降水数据解析 = js2xml.parse(脚本)打印 js2xml.pretty_print(解析)

这给了你:

<预><代码><程序><函数调用><功能><标识符名称="$"/></功能><参数><funcexpr><标识符/><参数/><身体><var name="chart"/><函数调用><功能><点访问器><对象><函数调用><功能><标识符名称="$"/></功能><参数><标识符名称=文档"/></参数></函数调用></对象><财产><标识符名称=就绪"/></属性></dotaccessor></功能><参数><funcexpr><标识符/><参数/><身体><assign operator="="><左><标识符名称=图表"/></左><右><新><点访问器><对象><标识符名称="Highcharts"/></对象><财产><标识符名称="图表"/></属性></dotaccessor><参数><对象><属性名称=图表"><对象><属性名称="renderTo"><string>tempchartcontainer</string></属性><属性名称=类型"><string>样条</string></属性></对象></属性><财产名称=信用"><对象><属性名称=启用"><boolean>false</boolean></属性></对象></属性><属性名称=颜色"><阵列><string>#FF8533</string><string>#4572A7</string></阵列></属性><属性名称=标题"><对象><属性名称=文本"><string>布鲁塞尔的平均温度 (°c) 图表</string></属性></对象></属性><属性名称="xAxis"><对象><属性名称=类别"><阵列><string>一月</string><string>二月</string><string>三月</string><string>四月</string><string>可能</string><string>六月</string><string>七月</string><string>八月</string><string>九月</string><string>十月</string><string>十一月</string><string>十二月</string></阵列></属性><属性名称=标签"><对象><属性名称=旋转"><数值=270"/></属性><属性名称=y"><数值=40"/></属性></对象></属性></对象></属性><属性名称="yAxis"><对象><属性名称=标题"><对象><属性名称=文本"><string>温度 (°c)</string></属性></对象></属性></对象></属性><属性名称=工具提示"><对象><属性名称=启用"><boolean>true</boolean></属性></对象></属性><属性名称="plotOptions"><对象><属性名称=样条"><对象><属性名称=数据标签"><对象><属性名称=启用"><boolean>true</boolean></属性></对象></属性><属性名称=启用鼠标跟踪"><boolean>false</boolean></属性></对象></属性></对象></属性><属性名称=系列"><阵列><对象><属性名称=名称"><string>平均高温 (°c)</string></属性><属性名称=颜色"><string>#FF8533</string></属性><属性名称=数据"><阵列><数值=6"/><数值=8"/><数值=11"/><数值=14"/><数值=19"/><数值=21"/><数值=23"/><数值=23"/><数值=19"/><数值=15"/><数值=9"/><数值=6"/></阵列></属性></对象><对象><属性名称=名称"><string>平均低温 (°c)</string></属性><属性名称=颜色"><string>#4572A7</string></属性><属性名称=数据"><阵列><数值=2"/><数值=2"/><数值=4"/><数值=6"/><数值=10"/><数值=12"/><数值=14"/><数值=14"/><数值=11"/><数值=8"/><数值=5"/><数值=2"/></阵列></属性></对象></阵列></属性></对象></参数></新></右></assign></funcexpr></参数></函数调用></funcexpr></参数></函数调用></程序>

所以要获取所有数据:

In [28]: from bs4 import BeautifulSoup在 [29]:导入请求在 [30] 中:导入重新在 [31] 中:导入 js2xml在 [32] 中:从 itertools 导入重复在 [33]: from pprint import pprint as pp在 [34]: 汤 = BeautifulSoup(requests.get("http://www.worldweatheronline.com/brussels-weather-averages/be.aspx").content, "html.parser")在 [35] 中:script =soup.find("script", text=re.compile("Highcharts.Chart")).text在 [36] 中:解析 = js2xml.parse(script)在 [37] 中:data = [d.xpath(".//array/number/@value") for d in parsed.xpath("//property[@name='data']")]在 [38] 中:categories = parsed.xpath("//property[@name='categories']//string/text()")在 [39]: output = list(zip(repeat(categories), data))在 [40] 中:pp(输出)[(['一月','二月','行进','四月','可能','六月','七月','八月','九月','十月','十一月','十二月'],['6', '8', '11', '14', '19', '21', '23', '23', '19', '15', '9', '6']),(['一月','二月','行进','四月','可能','六月','七月','八月','九月','十月','十一月','十二月'],['2', '2', '4', '6', '10', '12', '14', '14', '11', '8', '5', '2'])]

就像我说的,你可以只使用正则表达式,但 js2xml 我发现它更可靠,因为错误的空格等不会破坏它.

I want to scrape the data from a page that shows a graph using highcharts.js, and thus I finished to parse all the pages to get to the following page. However, the last page, the one that displays the dataset, uses highcharts.js to show the graph, which it seems to be near impossible to access to the raw data.

I use Python 3.5 with BeautifulSoup.

Is it still possible to parse it? If so how can I scrape it?

解决方案

The data is in a script tag. You can get the script tag using bs4 and a regex. You could also extract the data using a regex but I like using /js2xml to parse js functions into a xml tree:

from bs4 import BeautifulSoup
import requests
import re
import js2xml

soup = BeautifulSoup(requests.get("http://www.worldweatheronline.com/brussels-weather-averages/be.aspx").content, "html.parser")
script = soup.find("script", text=re.compile("Highcharts.Chart")).text
# script = soup.find("script", text=re.compile("precipchartcontainer")).text if you want precipitation data
parsed = js2xml.parse(script)
print js2xml.pretty_print(parsed)

That gives you:

<program>
  <functioncall>
    <function>
      <identifier name="$"/>
    </function>
    <arguments>
      <funcexpr>
        <identifier/>
        <parameters/>
        <body>
          <var name="chart"/>
          <functioncall>
            <function>
              <dotaccessor>
                <object>
                  <functioncall>
                    <function>
                      <identifier name="$"/>
                    </function>
                    <arguments>
                      <identifier name="document"/>
                    </arguments>
                  </functioncall>
                </object>
                <property>
                  <identifier name="ready"/>
                </property>
              </dotaccessor>
            </function>
            <arguments>
              <funcexpr>
                <identifier/>
                <parameters/>
                <body>
                  <assign operator="=">
                    <left>
                      <identifier name="chart"/>
                    </left>
                    <right>
                      <new>
                        <dotaccessor>
                          <object>
                            <identifier name="Highcharts"/>
                          </object>
                          <property>
                            <identifier name="Chart"/>
                          </property>
                        </dotaccessor>
                        <arguments>
                          <object>
                            <property name="chart">
                              <object>
                                <property name="renderTo">
                                  <string>tempchartcontainer</string>
                                </property>
                                <property name="type">
                                  <string>spline</string>
                                </property>
                              </object>
                            </property>
                            <property name="credits">
                              <object>
                                <property name="enabled">
                                  <boolean>false</boolean>
                                </property>
                              </object>
                            </property>
                            <property name="colors">
                              <array>
                                <string>#FF8533</string>
                                <string>#4572A7</string>
                              </array>
                            </property>
                            <property name="title">
                              <object>
                                <property name="text">
                                  <string>Average Temperature (°c) Graph for Brussels</string>
                                </property>
                              </object>
                            </property>
                            <property name="xAxis">
                              <object>
                                <property name="categories">
                                  <array>
                                    <string>January</string>
                                    <string>February</string>
                                    <string>March</string>
                                    <string>April</string>
                                    <string>May</string>
                                    <string>June</string>
                                    <string>July</string>
                                    <string>August</string>
                                    <string>September</string>
                                    <string>October</string>
                                    <string>November</string>
                                    <string>December</string>
                                  </array>
                                </property>
                                <property name="labels">
                                  <object>
                                    <property name="rotation">
                                      <number value="270"/>
                                    </property>
                                    <property name="y">
                                      <number value="40"/>
                                    </property>
                                  </object>
                                </property>
                              </object>
                            </property>
                            <property name="yAxis">
                              <object>
                                <property name="title">
                                  <object>
                                    <property name="text">
                                      <string>Temperature (°c)</string>
                                    </property>
                                  </object>
                                </property>
                              </object>
                            </property>
                            <property name="tooltip">
                              <object>
                                <property name="enabled">
                                  <boolean>true</boolean>
                                </property>
                              </object>
                            </property>
                            <property name="plotOptions">
                              <object>
                                <property name="spline">
                                  <object>
                                    <property name="dataLabels">
                                      <object>
                                        <property name="enabled">
                                          <boolean>true</boolean>
                                        </property>
                                      </object>
                                    </property>
                                    <property name="enableMouseTracking">
                                      <boolean>false</boolean>
                                    </property>
                                  </object>
                                </property>
                              </object>
                            </property>
                            <property name="series">
                              <array>
                                <object>
                                  <property name="name">
                                    <string>Average High Temp (°c)</string>
                                  </property>
                                  <property name="color">
                                    <string>#FF8533</string>
                                  </property>
                                  <property name="data">
                                    <array>
                                      <number value="6"/>
                                      <number value="8"/>
                                      <number value="11"/>
                                      <number value="14"/>
                                      <number value="19"/>
                                      <number value="21"/>
                                      <number value="23"/>
                                      <number value="23"/>
                                      <number value="19"/>
                                      <number value="15"/>
                                      <number value="9"/>
                                      <number value="6"/>
                                    </array>
                                  </property>
                                </object>
                                <object>
                                  <property name="name">
                                    <string>Average Low Temp (°c)</string>
                                  </property>
                                  <property name="color">
                                    <string>#4572A7</string>
                                  </property>
                                  <property name="data">
                                    <array>
                                      <number value="2"/>
                                      <number value="2"/>
                                      <number value="4"/>
                                      <number value="6"/>
                                      <number value="10"/>
                                      <number value="12"/>
                                      <number value="14"/>
                                      <number value="14"/>
                                      <number value="11"/>
                                      <number value="8"/>
                                      <number value="5"/>
                                      <number value="2"/>
                                    </array>
                                  </property>
                                </object>
                              </array>
                            </property>
                          </object>
                        </arguments>
                      </new>
                    </right>
                  </assign>
                </body>
              </funcexpr>
            </arguments>
          </functioncall>
        </body>
      </funcexpr>
    </arguments>
  </functioncall>
</program>

So to get all the data:

In [28]: from bs4 import BeautifulSoup  
In [29]: import requests
In [30]: import re    
In [31]: import js2xml    
In [32]: from itertools import repeat    
In [33]: from pprint import pprint as pp
In [34]: soup = BeautifulSoup(requests.get("http://www.worldweatheronline.com/brussels-weather-averages/be.aspx").content, "html.parser")

In [35]: script = soup.find("script", text=re.compile("Highcharts.Chart")).text

In [36]: parsed = js2xml.parse(script)

In [37]: data = [d.xpath(".//array/number/@value") for d in parsed.xpath("//property[@name='data']")]

In [38]: categories = parsed.xpath("//property[@name='categories']//string/text()")

In [39]: output =  list(zip(repeat(categories), data))    
In [40]: pp(output)
[(['January',
   'February',
   'March',
   'April',
   'May',
   'June',
   'July',
   'August',
   'September',
   'October',
   'November',
   'December'],
  ['6', '8', '11', '14', '19', '21', '23', '23', '19', '15', '9', '6']),
 (['January',
   'February',
   'March',
   'April',
   'May',
   'June',
   'July',
   'August',
   'September',
   'October',
   'November',
   'December'],
  ['2', '2', '4', '6', '10', '12', '14', '14', '11', '8', '5', '2'])]

Like I said you could just use a regex but js2xml I find is more reliable as erroneous spaces etc.. won't break it.

这篇关于我可以从 highcharts.js 中抓取原始数据吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆