数据库设计
数据库省份表(province)
城市表(city)
Python代码
import requests
from lxml import etree
import pymysql
from fake_useragent import UserAgent
#请求方法
def request(param):
url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2018/'
url = url + param
# 伪装
ua = UserAgent()
headers = {'User-Agent':ua.random}
response = requests.get(url=url,headers=headers)
# 获取字符集编码
response.encoding = response.apparent_encoding
data = response.text
# 将源码数据加载到数据对象中
data = etree.HTML(data)
return data
param = 'index.html'
data = request(param)
#省份数据列表
province_data = []
#城市数据列表
city_data = []
province_list = data.xpath('//tr[@class="provincetr"]/td')
for provinceli in province_list:
province = provinceli.xpath('./a/text()')[0]
#获取省份下一级链接
next_src =provinceli.xpath('./a/@href')[0]
#获取省份id值,为城市表的外键
province_id = next_src.split('.')[0]
print('-----------' + province + '爬取成功,进入城市爬取-----------')
#对省份数据进行切片、数据转换处理
# 思路
# 1、先创建一个空的列表
# 2、根据省份表的需要,将省份id、名字添加到空的列表中
# 3、将添加过后的列表转化为元组
# 4、将转换后的元祖添加到全局列表中(列表名称为:级别 + _data)
pro_data = []
pro_data.append(province_id)
pro_data.append(province)
pro_data = tuple(pro_data)
province_data.append(pro_data)
#进入城市查询
data = request(next_src)
city_list = data.xpath('//tr[@class="citytr"]')
for cityli in city_list:
city_name = cityli.xpath('./td[2]/a/text()')[0]
# 获取城市下一级链接
city_next_src = cityli.xpath('./td[1]/a/@href')[0]
# 获取城市id
city_id = cityli.xpath('./td[1]/a/text()')[0]
print(city_name + city_next_src + city_id + ' 爬取成功!!')
# 对城市数据进行切片、数据转换处理
# 思路
# 1、先创建一个空的列表
# 2、根据城市表的需要,将城市id、名字、上一级省份ID(省份,城市这两个页面比较特殊)添加到空的列表中
# 3、将添加过后的列表转化为元组
# 4、将转换后的元祖添加到全局列表中(列表名称为:级别 + _data)
#---cit_data 的名字要与全局city_data区分开,起名有点相似 cit_data != city_data
cit_data = []
up_id = city_next_src.split('/')[0] #城市表上一级id(外键)
new_src = city_next_src.split('/')[1] #城市下一级
cit_data.append(city_id)
cit_data.append(city_name)
cit_data.append(up_id)
# print(cit_data)
cit_data = tuple(cit_data)
city_data.append(cit_data)
print(province_data)
#连接数据库
connecion =pymysql.connect (
host='localhost', # 数据库地址
user='root', # 数据库用户名
password='19981216', # 数据库密码
db='china', # 数据库名称
)
cursor = connecion.cursor()
province_sql = 'insert into province(province_id,province_name) values (%s,%s)'
city_sql = 'insert into city(city_id,city_name,up_id) values (%s,%s,%s)'
cursor.executemany(province_sql,province_data)
connecion.commit()
print(cursor.rowcount)
cursor.executemany(city_sql,city_data)
connecion.commit()
print(cursor.rowcount)
cursor.close()
connecion.close()
总结:
- 利用xpath解析的时候,一定要把路径写正确。一直以为省份和城市的数据解析路径一样,然后就一直解析不出来
- 使用了fake_useragent浏览器伪装库,但是因为这是换了浏览器的user-Agent,ip地址并没有更换,所以当你多次运行程序时,会受到反爬虫机制的影响,抓不到数据。
- 同步爬取,效率低,数据量小的时候感觉不出来,把国家统计局中的信息爬取到village的时候,你就会知道有多慢了(亲自测试过一个省份的所有下级信息)。
推荐一个大佬的反爬虫机制策略:
https://blog.csdn.net/ITBigGod/article/details/103248172