python利用高德接口,爬取武汉地区的POI--一个不太成熟的BUG,程序总是跑着跑着就假死了。

说明
1.遇到的问题

可是爬取过程中总是不顺利,程序总是爬着爬着就不动了,有时爬几千条假死,有时爬几万条假死。数据库中没有新数据增加,程序也不报错,也不中止。CPU,内存占用也不高,硬盘中也还有空间,现在是实在不知道如何解决了。所以想让请教一番。

2.需求背景

毕业设计需要用到一些城市的POI数据,本着自己动手丰衣足食的原则,就从自己写了段python代码从高德地图爬取POI数据。

3.高德获取POI数据接口说明
多边形搜索API接口,请求方式get

https://restapi.amap.com/v3/place/polygon?
//请求参数:

polygon:如果多边形为矩形,则需要左上,右下经纬度坐标
左上角:113.705304,31.366201
右下角:115.089744,29.974252
以上为例,polygon = 113.705304,31.366201|115.089744,29.974252

types=010000:POI数据的地物类型  ,比如汽车服务,居民住宅等

offset=10,每页返回的数据量,最大为25

page=1,页码从0开始,第0页和第1页相同,最大100
补充:接口文档说一个区域最多1000个数据,实测只有800多数据。
4.代码思路

由于一个区域只能获取800多数据。

因此当对一个矩形区域进行爬取时,
	如果返回的数据大于800,则认为该区域的POI数据超过接口规定上限,对该区域进行四等分,然后再逐个进行爬取。
	如果返回的数据小于800,则认为已经获取了该区域所有的POI,将这些POI写入mysql数据库。
代码
运行环境

IDE:pycharm3.3
环境:python3.6
系统:64bit win10
内存:16G
CPU:i7 7700hq
数据库:mysql

源码
import requests
import pymysql
import time
import math
import socket

''' 
    https://restapi.amap.com/v3/place/polygon?polygon=113.705304,31.366201|115.089744,29.974252&key=10518669c9fd0a0532e41189d61e1e9b&extensions=all&types=010000&offset=10&page=90
'''
# 初始区域的经纬度
lon_l = 113.705304
lan_l = 31.366201
lon_r = 115.089744
lan_r = 29.974252

# 要爬取POI的类型
types = '010000|020000|030000|040000|050000|060000|' \
        '070000|080000|090000|100000|110000|120000|' \
        '130000|140000|150000|160000|170000|180000|' \
        '190000|200000|210000|220000|230000|240000|' \
        '970000|990000'

# 获取POI的接口
url = 'https://restapi.amap.com/v3/place/polygon?' \
     'polygon={lon_l},{lan_l}|{lon_r},{lan_r}' \
     '&key=10518669c9fd0a0532e41189d61e1e9b&extensions=all' \
     '&types={types}&offset=25&page={page}'


# point
class Point:
    """
    用经纬度来描述一个点
    """
    def __init__(self, lon, lan):
        self.lon = lon      # 经度
        self.lan = lan      # 纬度


# area
class Rectangle:
    """
    用左上角的经纬度和右下角的经纬度描述一个矩形区域
    """
    def __init__(self, p_l, p_r):
        self.p_l = p_l      # 左上角的点
        self.p_r = p_r      # 右下角的点


# 初始矩形的左上点和右下点
p_l = Point(lon_l,lan_l)
p_r = Point(lon_r,lan_r)

# 初始矩形,內含两点,左上,右下
rec = Rectangle(p_l,p_r)

'''
打开一个URL,获取返回信息
'''
def open_html(real_url):
    NET_STATUS=False
    while not NET_STATUS:
        try:
            data = requests.get(real_url).json()
            return data
        except socket.timeout:
            print("NET_STATURS IS NOT GOOD")
            NET_STATUS=False
        except :
            print("OTHER WRONG")



# 把一个区域的POI点存进数据库
def get_pois(rec,url,data_count):
    url = url.format(lon_l = rec.p_l.lon , lan_l = rec.p_l.lan ,
               lon_r = rec.p_r.lon , lan_r = rec.p_r.lan ,
               types = types,page="{page}")

    f_url = open("url.txt","a",encoding="UTF-8")

    data= open_html(url.format(page=0))

    if data["status"] == "1":
        # 执行到这里,说明url中含有poi数据,下面开始爬取
        all_page=math.ceil(data_count/25)
        for page in range(all_page):
            try:
                # 从第1页开始到第最后一页
                url_real = url.format(page = page+1)
                f_url.write(url_real+'\n')
                data = open_html(url_real)
                if data["status"] == "1" : # 判断第page+1页是否有内容
                    pois = data["pois"]

                    # 将数据储存在数据库
                    # 优化点:db先创建好,一次用完不关,最后再关
                    global db_global
                    db = db_global
                    cursor = db.cursor()
                    str_sql = 'insert into t_poi(id,name,address,typecode,lon,lan,pcode,pname,citycode,cityname,adcode,adname) ' \
                              'values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'
                    count=0
                    for poi in pois:
                        try:
                            count += 1
                            value = [poi['id'], poi['name'], poi["address"], poi['typecode'],
                                     poi['location'].split(',')[0], poi['location'].split(',')[1],
                                     poi['pcode'], poi['pname'], poi['citycode'], poi['cityname'], poi['adcode'], poi['adname']]

                            if [] in value:
                                value[value.index([])]=''

                            try:
                                cursor.execute(str_sql,value)
                                db.commit()
                            except:
                                Exception
                                # 打印日志文件
                                f=open("wrong.txt",'a',encoding="UTF-8")
                                time_fomat = '%Y-%m-%d %X'
                                time_current = time.strftime(time_fomat)
                                f.write(time_current+ '  第{page}页,第{index}个出错\n'.format(page=page,index=count))
                        except:
                            pass

                    cursor.close()
            except:
                pass


#检测器
run_count = 0


# 爬取,分析一个区域的POI数量,多于800则将区域四等分,并递归,低于800则进行爬取
def crawl_pois(rec,url):

    # 计算进行了几次分析的计数器,判断程序是否卡死
    global run_count;
    run_count += 1;
    f_count = open("count.txt",'a',encoding="UTF-8");
    f_count.write("这是第{_count}次运行分析一个区域\n".format(_count=run_count))

    # 根据矩形区域的经纬度坐标,拼接url
    url_real = url.format(lon_l=rec.p_l.lon, lan_l=rec.p_l.lan,
                     lon_r=rec.p_r.lon, lan_r=rec.p_r.lan,
                     types=types, page="{page}")

    # 获取url返回的数据
    data = open_html(url_real.format(page=0))

    if data["status"] == "1":
        # 执行到这里,说明url中含有poi数据,下面开始判断区域POI数量
        data_count = int(data['count'])
        if  data_count> 800:
            # 如果区域POI数据大于800则进行四等分
            rec_A = Rectangle(Point(0,0),Point(0,0))
            rec_B = Rectangle(Point(0,0),Point(0,0))
            rec_C = Rectangle(Point(0,0),Point(0,0))
            rec_D = Rectangle(Point(0,0),Point(0,0))

            # 经纬度差
            lon_d = (rec.p_r.lon - rec.p_l.lon)/2
            lan_d = (rec.p_l.lan - rec.p_r.lan)/2

            # 计算每个小矩形的左上点,和右下点
            rec_A.p_l.lon = float(format(rec.p_l.lon,'6f'))
            rec_A.p_l.lan = float(format(rec.p_l.lan,'6f'))
            rec_A.p_r.lon = float(format(rec.p_l.lon + lon_d,'6f'))
            rec_A.p_r.lan = float(format(rec.p_r.lan + lan_d,'6f'))

            rec_B.p_l.lon = float(format(rec.p_l.lon + lon_d,"6f"))
            rec_B.p_l.lan = float(format(rec.p_l.lan,"6f"))
            rec_B.p_r.lon = float(format(rec.p_r.lon,"6f"))
            rec_B.p_r.lan = float(format(rec.p_r.lan + lan_d,"6f"))

            rec_C.p_l.lon = float(format(rec.p_l.lon,"6f"))
            rec_C.p_l.lan = float(format(rec.p_r.lan + lan_d,"6f"))
            rec_C.p_r.lon = float(format(rec.p_l.lon + lon_d,"6f"))
            rec_C.p_r.lan = float(format(rec.p_r.lan,"6f"))

            rec_D.p_l.lon = float(format(rec.p_l.lon + lon_d,"6f"))
            rec_D.p_l.lan = float(format(rec.p_r.lan + lan_d,"6f"))
            rec_D.p_r.lon = float(format(rec.p_r.lon,"6f"))
            rec_D.p_r.lan = float(format(rec.p_r.lan,"6f"))

            recs = []
            recs.append(rec_A)
            recs.append(rec_B)
            recs.append(rec_C)
            recs.append(rec_D)

            # 对四个小矩形分别进行爬取,这里使用递归
            for rec_s in recs :
                # 如果一个区域出现异常,就进行下个区域
                try:
                    crawl_pois(rec_s,url)
                except:
                    pass

        else:
            # 如果该矩形区域poi点的数量少于800就进行爬取
            get_pois(rec,url,data_count)

    else:
        print("出错")

'''
下面是程序的入口
'''
# 创建一个全局的连接
db_global = pymysql.connect("localhost", "root", "111111", "poi")

# 对一个矩形进行爬取分析,这里是对武汉地区的左上角和右下角的经纬度围成的矩形进行爬取
crawl_pois(rec,url)

# 关闭数据库
db_global.close()


代码的思路我自我感觉没什么大问题,递归也有出口,就是程序跑着跑着就假死了,我也不能确定到底是哪里有问题,路过的大手子们

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值