python 爬取七普人口并展示人口区间的概率分布

爬虫常用的库:requests,beautifulsoup,urllib2,scrapy等,本次主要用requests库以及正则表达式提取关键信息。

正态分布有一个非常重要的性质:在特定条件下,大量统计独立的随机变量的和的分布趋于正态分布,这就是中心极限定理。

为了验证中心极限定律,想着爬取七普人口,统计各个人口范围区间内的城市数量,观察直方图,结果查了好多网站也没找到现成的人口数量,最后最后在买购网上看到有按省份给出的地市人口数量。但是各个省份的人口需要点击进去查看,而且少了新疆的人口。

打开F12,可以看到调用接口的返回内容。用requests 调用接口,获取的内容和F12中查到的内容一致。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pig5LmLMTIz,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pig5LmLMTIz,size_20,color_FFFFFF,t_70,g_se,x_16

如点击左边的黑龙江各市人口排行榜,页面会打开"https://www.maigoo.com/news/494583.html"

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pig5LmLMTIz,size_20,color_FFFFFF,t_70,g_se,x_16

一个一个点开页面再统计,会是对人性的压抑,所以这里通过正则表达式提取出url和对应的省份。观察发现省份的url前缀为https://www.maigoo.com/news/或https://www.maigoo.com/top/两种,而除了北京,对应的省份名称都有省份名+各,用各进行精确匹配出省份名。所以正则中用| 符匹配出url和省份,最后生成的是数组列表,数组包含url和省份名。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pig5LmLMTIz,size_20,color_FFFFFF,t_70,g_se,x_16

匹配出的结果如下:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pig5LmLMTIz,size_15,color_FFFFFF,t_70,g_se,x_16

最后用replace把“各”字去掉。

用爬虫的方法查询各个省份地市人口数据,需要重定向省份的url,然后再次依次调用url,获取数据。

 依次调用省份的url,提取各个省份城市名称及其对应的人口数量。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pig5LmLMTIz,size_20,color_FFFFFF,t_70,g_se,x_16

提取城市名和人口数量时,调用接口获取的内容进行正则匹配,观察url发现城市和人口数量在url中的位置如下:

80c2bf377447478fae724e528264a676.png

但是不是所有的都这样,内容也有如下存放的:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pig5LmLMTIz,size_17,color_FFFFFF,t_70,g_se,x_16

所以正则匹配的时候,用.*? 既可以匹配到多出来的<span>中的内容,没有这部分内容也能匹配到城市名和人口数。

 匹配出的城市名和人口数量保存到city、count

最后把提取的人口保存为excel文件。同时查询并补充上新疆的人口。

爬取人口代码如下:


import requests
import time,datetime
import pandas as pd
import random
import json,re
from fake_useragent import UserAgent
import openpyxl

items = [
    {'http': 'http://171.35.171.247:9999'}
]
headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    'Connection': "keep-alive",
    'User-Agent': UserAgent().random
}
proxies = random.choice(items)
url = "https://www.maigoo.com/goomai/223462.html"       #麦客网爬取各城市七普人口
html = requests.get(url,headers=headers,proxies=proxies,verify=False)
content = html.content.decode('utf-8')
title_city = re.findall(r'><a href="(https://www.maigoo.com/news/\d+.html|https://www.maigoo.com/top/\d+.html)" target="_blank" class="blue">(\w+各|北京)\w+', content)  #正则匹配

census = pd.DataFrame(columns=['city','provence','count'])  #城市名称,省份,人口数量
for  i in range(31):
    url_city = title_city[i][0]
    provence_name = title_city[i][1].replace("各","")
    proxies = random.choice(items)
    try:
        time.sleep(1)
        html = requests.get(url_city, headers=headers, proxies=proxies, verify=False)
        provence =  html.content.decode('utf-8')
        peopel_city = re.findall(r'<h3.*>\n.*?(\w+)\((\d+.*)万人\).*\n</h3>',provence)
        for item in peopel_city:
            census = census.append({'city':item[0],'provence':provence_name, 'count':item[1]},ignore_index=True)
        print(census.shape)
    except:
        continue
census.to_excel("各城市人口2.xlsx",index=False)

最后用pandas的cut 方法按区间统计出每个区间有多少城市,比如大于1600万人口的城市有6座。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pig5LmLMTIz,size_20,color_FFFFFF,t_70,g_se,x_16

没有筛选处理时区间分布直方图如下:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pig5LmLMTIz,size_20,color_FFFFFF,t_70,g_se,x_16

 除去直辖市,把海南的几个县合并到一起,再进行统计。直方图如下:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pig5LmLMTIz,size_20,color_FFFFFF,t_70,g_se,x_16

观察该图,发现该图有点像接近高斯分布。

import numpy
import pandas as pd
import matplotlib.pyplot as plt
from pyecharts.charts import Bar
from pyecharts import options as opts

data = pd.read_excel("各城市人口2.xlsx")
data = pd.DataFrame(data)
people_count = data['count'].values.tolist()
range_num = []
labes = []
j = 1
for i in range(0,1700,100):
    range_num.append(i)
    labes.append(str(i)+"-"+str(j*100))
    j+=1
range_num.append(5000)
labes.pop(-1)
labes.append("大于1600")
print(range_num,labes)
cuts = pd.cut(people_count,range_num,labels=labes)
couts_range = cuts.value_counts().values.tolist()

bar = Bar(init_opts=opts.InitOpts(width="2000px",height="700px",page_title="各个区间范围的城市数"))
bar.add_xaxis(labes)
bar.add_yaxis("", couts_range)
bar.set_global_opts(
    xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=20)),
    title_opts=opts.TitleOpts(title="区间内的城市数量", subtitle="坐"),
    datazoom_opts=opts.DataZoomOpts(),
)

bar.render_notebook()
bar.render('全国区间人口2.html')

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

映之123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值