python3使用Selenium+Chrome+BeautifulSoup爬取国家统计局数据

本文介绍了一种使用selenium和beautifulsoup爬取国家统计局网站上固定资产与房地产月度数据的方法,通过模拟Chrome浏览器操作,获取并解析2013-2017年间各省份的数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

爬取目标:地区数据--分省月度数据--指标(固定资产、房地产)--维度(2013-2017)

最终代码GIT:https://github.com/sunruzi/python3

此处省略数据网址图片(与csdn界面主题风格相差甚远,有些咋眼)

数据网址:https://link.jianshu.com/?t=http%3A%2F%2Fdata.stats.gov.cn%2Feasyquery.htm%3Fcn%3DE0101

使用浏览器自带的开发者工具,观察一下需要爬取的页面,发现需要采集的数据是使用js生成的,这样是无法通过requests直接获取数据的。在这里我没有去解析请求获取数据的js代码块,而是采取了通过selenium模拟操作chrome浏览器,获得渲染后的页面,再使用beautifulsoup对源码进行解析,抓取需要的数据。

可能有小伙伴要问了,chrome是浏览器,这个不必多说;这selenium跟beautifulsoup是什么鬼?selenium其实是一款web自动测试工具,它可以模拟用户的操作,在我们的例子里点击按钮靠的就是它,当然它还有很多功能,在后面会提到;beautifulsoup是一个能从XML或HTML中提取数据的python库,功能强大,使用简单,是一款不可多得的好工具。

思路与使用的工具就先介绍到这,下面可以动手了!

首先引入需要使用的模块:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
from time import sleep
import pandas as pd

在这里需要说明一下,引入pandas是因为在网页中每个省的数据是单独展示的,需要在取完一个子指标中所有数据后将所有省市的数据合并为一个文件,这时就需要用到pandas的concat方法了。

观察一下我们需要爬取的页面,其实省市以及父指标子指标都是固定的(这是国家统计的数据,应该不会随意调整),这样其实可以把需要爬取的数据的标签拿出来拼成参数列表(其实可以直接从页面上抓取指定标签下的内容,这里偷了个懒。。。)。不过这里需要注意的是,固定资产投资与房地产投资下的子指标的标签id不是固定的,也是根据js生成的。

  AREAS = ['110000', '120000', '130000', '140000', '150000', '210000','220000', '230000', '310000', '320000', '330000', '340000','350000', '360000', '370000', '410000', '420000', '430000','440000', '450000', '460000', '500000', '510000', '520000','530000', '540000', '610000', '620000', '630000', '640000','650000']
  FATHERPOINTS = ['treeZhiBiao_6_a', 'treeZhiBiao_7_a']
  SONPOINTS1 = ['treeZhiBiao_9', 'treeZhiBiao_10', 'treeZhiBiao_11']
  SONPOINTS2 = ['treeZhiBiao_9', 'treeZhiBiao_10', 'treeZhiBiao_11', 'treeZhiBiao_12', 'treeZhiBiao_13']
  tree1 = [FATHERPOINTS[0], SONPOINTS1, AREAS]
  tree2 = [FATHERPOINTS[1], SONPOINTS2, AREAS]
  TargetPath = [tree1, tree2]

接下来写一个自动操作的方法:

def source_code(fatherPoint, sonPoint, areaCode):
    #chrome设置为headless模式,也就是无界面浏览器。在window下需要同时设置--disable-gpu
    chrome_options = Options()
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--disable-gpu')
    #如果想要看到底是怎么模拟的,可以只使用webdriver.Chrome()
    browser = webdriver.Chrome(chrome_options=chrome_options)
    try:
        #浏览器打开目标url
        browser.get('http://data.stats.gov.cn/easyquery.htm?cn=E0101')
        #这里采用了一个显式等待
        locator = (By.XPATH, '//div[@class="mr-content"]')
        WebDriverWait(browser, 20, 0.5).until(
        EC.presence_of_element_located(locator))
        #这里为啥要用一个强制等待呢?因为如果这里不加强制等待会找不到元素,也可能是我设置的有问题
        sleep(1)
        #点击父指标
        browser.find_element(
            By.XPATH, '//a[@id="{}"]'.format(fatherPoint)).click()
        sleep(1)
        #点击子指标
        browser.switch_to.window(browser.window_handles[0])
        browser.find_element(
            By.XPATH, '//li[@id="{}"]'.format(sonPoint)).click()
        #点击地区的下拉按钮
        browser.find_element(
            By.XPATH, '//div[@id="mySelect_reg"]/div[@class="dtHtml"]/div[@class="dtHead"]').click()
        #点击需要查看的地区
        browser.find_element(
            By.XPATH, '//div[@id="mySelect_reg"]/div[@class="dtHtml"]/div[@class="dtBody"]/div[@class="dtList"]/ul/li[@code="{}"]'.format(areaCode)).click()
        #点击时间的下拉按钮
        browser.find_element(
            By.XPATH, '//div[@id="mySelect_sj"]/div[@class="dtHtml"]/div[@class="dtHead"]').click()
        #在指定时间的栏内填入需要查询的时间区间,并点击确定
        browser.find_element(
            By.XPATH, '//div[@id="mySelect_sj"]/div[@class="dtHtml"]/div[@class="dtBody"]/div[@class="dtFoot"]/input[@class="dtText"]').send_keys("2013-2017")
        browser.find_element(By.XPATH, '//div[@class="dtTextBtn"]').click()
        #获取渲染后的网页代码
        sourceCode = browser.page_source
        browser.quit()
        return sourceCode
    finally:
        browser.quit()

然后再写一个解析网页的方法:

def annalysis_source_code(source_code, sonPoint):
    #获取当前抓取父指标的名称作为文件名
    global name
    soup = BeautifulSoup(source_code, 'lxml')
    region = soup.select(
        'div[id="mySelect_reg"] > div[class="dtHtml"] > div[class="dtHead"]')[0].get_text()
    print(region)
    name = soup.select('li[id="{}"] > a'.format(sonPoint))[0].get("title")
    headers = []
    #获取表格数据体
    headerArr = soup.select(
        'table[class="public_table table_fix"] > thead > tr[class="tr-title"] > th')
    for i in headerArr:
        headers.append(i.span['code'])
    tables = []
    rowArr = soup.select('table[class="public_table table_fix"] > tbody > tr')
    for rowSoup in rowArr:
        blocks = []
        row = rowSoup.select('td')
        for i in row:
            blocks.append(i.get_text())
        tables.append(blocks)
    #创建dataframe,并转置(因为爬下来的数据列名都是日期,转置一下看起来比较数据)
    df = pd.DataFrame(tables, columns=headers)
    df = df.T
    columnName = df.ix['zb'].values.tolist()
    df.columns = columnName
    df = df.drop(['zb'])
    df['region'] = region
    return df

完整代码请移步原作者的git项目:https://github.com/DeathShort/python-clawer-for-national-bureau-of-statistics

原文链接:https://www.jianshu.com/p/2575a8b93691

排查错误过程:

1.解决:'chromedriver' executable needs to be in PATH问题

https://blog.youkuaiyun.com/weixin_37185329/article/details/80493281

2.Python自动测试打开chrome时,chrome地址栏总是出现data:;

https://blog.youkuaiyun.com/m_eve/article/details/76284252

3.库pandas写入csv格式文件出现中文乱码问题解决方法

http://www.cnblogs.com/lizm166/p/9639168.html

4.搜到“”山东省“”报错找不到句柄,时如下:

江西省
--------360000 LOADED--------
Now loading:treeZhiBiao_7_a-treeZhiBiao_13-370000
Traceback (most recent call last):
  File "F:/python/爬取公家统计局数据.py", line 109, in <module>
    sourceCode = source_code(fatherPoint, sonPoint, area)
  File "F:/python/爬取公家统计局数据.py", line 47, in source_code
    By.XPATH, '//li[@id="{}"]'.format(sonPoint)).click()
  File "C:\Users\11046\AppData\Local\Programs\Python\Python36-32\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 978, in find_element
    'value': value})['value']
  File "C:\Users\11046\AppData\Local\Programs\Python\Python36-32\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
    self.error_handler.check_response(response)
  File "C:\Users\11046\AppData\Local\Programs\Python\Python36-32\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//li[@id="treeZhiBiao_13"]"}
  (Session info: headless chrome=71.0.3578.80)
  (Driver info: chromedriver=71.0.3578.80 (2ac50e7249fbd55e6f517a28131605c9fb9fe897),platform=Windows NT 10.0.17134 x86_64)

4.1解决Selenium弹出新页面无法定位元素问题(Unable to locate element)https://blog.youkuaiyun.com/mrlevo520/article/details/51926145 

4.2关于switch_to的用法(解决出现中划线)

https://blog.youkuaiyun.com/qq_41305167/article/details/80580805

原网址“房地产”下有5个子指标,需要修改代码,并增加一行:

#切换页面
        browser.switch_to.window(browser.window_handles[0])
        browser.find_element(
            By.XPATH, '//li[@id="{}"]'.format(sonPoint)).click()

执行成功: Process finished with exit code 0

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值