highway_distance.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import asyncio
  2. import json
  3. import aiohttp
  4. import urllib.parse
  5. import random
  6. from database import Database
  7. class HighwayDistanceCalculator:
  8. def __init__(self):
  9. self.db = Database()
  10. self.tianditu_key = "3b2d9954565a494ffab9cfd26d7fc522"
  11. self.base_url = "https://api.tianditu.gov.cn/v2/search"
  12. self.keywords = ["高速", "互通"]
  13. # 添加常见的User-Agent列表
  14. self.user_agents = [
  15. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
  16. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36",
  17. "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0",
  18. "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15"
  19. ]
  20. def convert_distance_to_meters(self, distance_str):
  21. """将距离字符串转换为米"""
  22. try:
  23. if 'km' in distance_str:
  24. # 如果是千米,转换为米
  25. return int(float(distance_str.replace('km', '')) * 1000)
  26. else:
  27. # 如果是米,直接转换
  28. return int(distance_str.replace('m', ''))
  29. except Exception as e:
  30. print(f"距离转换错误: {distance_str}, {str(e)}")
  31. return None
  32. async def get_nearest_distance(self, point_lonlat):
  33. """获取最近的距离"""
  34. all_pois = []
  35. for keyword in self.keywords:
  36. post_str = {
  37. "keyWord": keyword,
  38. "level": 12,
  39. "queryRadius": 5000,
  40. "pointLonlat": point_lonlat,
  41. "queryType": 3
  42. }
  43. # 120.38920002653107,30.221665152310052
  44. print(f"查询关键词: {keyword}, 坐标: {point_lonlat}")
  45. # 将postStr参数进行URL编码
  46. encoded_post_str = urllib.parse.quote(json.dumps(post_str))
  47. # 构建完整的URL
  48. url = f"{self.base_url}?postStr={encoded_post_str}&type=query&tk={self.tianditu_key}"
  49. # 随机选择一个User-Agent
  50. headers = {
  51. "User-Agent": random.choice(self.user_agents),
  52. "Accept": "application/json, text/plain, */*",
  53. "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
  54. "Accept-Encoding": "gzip, deflate, br",
  55. "Connection": "keep-alive",
  56. "Referer": "https://map.tianditu.gov.cn/",
  57. "Origin": "https://map.tianditu.gov.cn"
  58. }
  59. async with aiohttp.ClientSession() as session:
  60. try:
  61. async with session.get(url, headers=headers) as response:
  62. if response.status == 200:
  63. data = await response.json()
  64. if data.get("pois"):
  65. for poi in data["pois"]:
  66. distance_meters = self.convert_distance_to_meters(poi["distance"])
  67. if distance_meters is not None:
  68. all_pois.append({
  69. "distance": distance_meters,
  70. "name": poi["name"],
  71. "keyword": keyword
  72. })
  73. else:
  74. print(f"请求失败,状态码: {response.status}")
  75. print(f"URL: {url}")
  76. print(f"响应内容: {await response.text()}")
  77. except Exception as e:
  78. print(f"请求异常: {str(e)}")
  79. # 添加随机延迟,避免请求过于频繁
  80. # await asyncio.sleep(random.uniform(1, 3))
  81. # 按距离排序
  82. if all_pois:
  83. all_pois.sort(key=lambda x: x["distance"])
  84. print(f"找到最近的点: {all_pois[0]['name']} ({all_pois[0]['keyword']}), 距离: {all_pois[0]['distance']}米")
  85. return all_pois[0]["distance"]
  86. return None
  87. async def process_ecgap_klyzy(self):
  88. """处理ecgap_klyzy表数据"""
  89. sql = """
  90. SELECT
  91. id,
  92. ST_X(ST_Centroid(shape::geometry)) as center_x,
  93. ST_Y(ST_Centroid(shape::geometry)) as center_y
  94. FROM ecgap_klyzy
  95. WHERE shape IS NOT NULL
  96. """
  97. try:
  98. parcels = await self.db.execute_query(sql)
  99. for parcel in parcels:
  100. id = parcel["id"]
  101. center_x = parcel["center_x"]
  102. center_y = parcel["center_y"]
  103. # 构建中心点坐标字符串
  104. center_point = f"{center_x},{center_y}"
  105. # 获取最近距离
  106. distance = await self.get_nearest_distance(center_point)
  107. if distance is not None:
  108. # 更新数据库
  109. update_sql = f"""
  110. UPDATE ecgap_klyzy
  111. SET gsjl = {distance}
  112. WHERE id = '{id}'
  113. """
  114. await self.db.execute_transaction([update_sql])
  115. print(f"更新ecgap_klyzy表地块 ID: {id} 的最近距离为 {distance}米")
  116. # 添加随机延迟,避免请求过于频繁
  117. await asyncio.sleep(random.uniform(1, 3))
  118. except Exception as e:
  119. print(f"处理ecgap_klyzy表数据错误: {str(e)}")
  120. async def process_kzxxxgh(self):
  121. """处理kzxxxgh表数据"""
  122. sql = """
  123. SELECT
  124. id,
  125. ST_X(ST_Centroid(shape::geometry)) as center_x,
  126. ST_Y(ST_Centroid(shape::geometry)) as center_y
  127. FROM kzxxxgh
  128. WHERE shape IS NOT NULL
  129. """
  130. try:
  131. parcels = await self.db.execute_query(sql)
  132. for parcel in parcels:
  133. id = parcel["id"]
  134. center_x = parcel["center_x"]
  135. center_y = parcel["center_y"]
  136. # 构建中心点坐标字符串
  137. center_point = f"{center_x},{center_y}"
  138. # 获取最近距离
  139. distance = await self.get_nearest_distance(center_point)
  140. if distance is not None:
  141. # 更新数据库
  142. update_sql = f"""
  143. UPDATE kzxxxgh
  144. SET gsjl = {distance}
  145. WHERE id = '{id}'
  146. """
  147. await self.db.execute_transaction([update_sql])
  148. print(f"更新kzxxxgh表地块 ID: {id} 的最近距离为 {distance}米")
  149. # 添加随机延迟,避免请求过于频繁
  150. await asyncio.sleep(random.uniform(1, 3))
  151. except Exception as e:
  152. print(f"处理kzxxxgh表数据错误: {str(e)}")
  153. async def process_all_parcels(self):
  154. """处理所有地块数据"""
  155. try:
  156. await self.db.connect()
  157. # print("开始处理ecgap_klyzy表...")
  158. # await self.process_ecgap_klyzy()
  159. print("开始处理kzxxxgh表...")
  160. await self.process_kzxxxgh()
  161. except Exception as e:
  162. print(f"处理地块数据错误: {str(e)}")
  163. finally:
  164. await self.db.close()
  165. async def main():
  166. calculator = HighwayDistanceCalculator()
  167. await calculator.process_all_parcels()
  168. if __name__ == "__main__":
  169. asyncio.run(main())