使用python+playwright获取社区名称并查询经纬度

实现目标:

使用python+playwright批量获取天津市和平区(示例)所有社区数据(名称及经纬度)

前置条件:

1.获取数据的网站:

1)和平区--天津市和平区地名介绍

2)拾取坐标系统

2.编辑器:

VScode

3.第三方库下载:

pip install playwight

playwright install

pip pandas

实现步骤:

1.新建一个文件夹gis,包含2个文件(region.py、convers.py)

2.region.py:待运行的python文件

# 导入
from playwright.sync_api import Playwright, sync_playwright
import pandas as pd
import convers as llc
import os

#初始化
result1 = pd.DataFrame() # 初始化社区数据
result2 = pd.DataFrame() # 初始化查询结果
count = 0 #初始化社区个数



def run (playwright: Playwright) -> None:

  # 创建无头浏览器(后台爬取)
  browser = playwright.chromium.launch(headless=False)

  # 使用 selenium 如果要打开多个网页,需要创建多个浏览器,但是 playwright 中只需要创建多个上下文即可
  # 例如:content1 = browser.new_context()、content2 = browser.new_context() 分别去访问网页做处理
  content = browser.new_context()

  print("---------------------------------------------------------------")
  # 每个 content 就是一个会话窗口,可以创建自己的页面,也就是浏览器上的 tab 栏,在每个会话窗口中,可以创建多个页面,也就是多个 tab 栏
  # 例如:page1 = content.new_page()、page2 = content.new_page() 封面去访问页面
  page1 = content.new_page()
  global result1
  
  # 页面打开指定网址
  page1.goto('http://www.tcmap.com.cn/tianjin/hepingqu.html')
  #获取省市区名称
  region = page1.query_selector('h1').text_content()
  #定位社区列表的每一行
  item = page1.query_selector_all('//*[@id="page_left"]/table/tbody/tr')
  #遍历每一行数据
  for i in range(1,len(item)):
    #街道/乡/镇名称
    region_3 = item[i].query_selector('strong a').text_content()
    #街道/乡/镇区划代码
    facode_3 = item[i].query_selector('td:nth-child(2)').text_content()
    #社区/村名称的列表
    regionList_4 = item[i].query_selector_all('.l a, .le a, .l2 a')
    #数据整理
    for j in range (len(regionList_4)):
      name = regionList_4[j].text_content()
      busi_data = [
      {
          "name": name,
          "fadcode": facode_3,
          "fname": region_3
          }
      ]
      df = pd.DataFrame(busi_data)
      #将社区/村的数据合并在result1中
      result1 = pd.concat([result1, df], axis=0, ignore_index=True)
  
  print("社区名称查询完毕!下面开始查询经纬度:")    
  #获取社区名称的列表
  name_list = result1['name']
  page2 = content.new_page()
  page2.goto('https://api.map.baidu.com/lbsapi/getpoint/index.html')
  def get_poi_from_amap(amp):
    global result2
    global count
    # 找到百度输入框( locator 会自动识别传入的选择器是 css xpath .... 不需要像 selenium 指定 By.XPATH/ID 这样的 )
    page2.fill('//*[@id="localvalue"]', amp)
    # 点击百度地图地址输入框进行搜索
    # page.locator('//input[@id="su"]').click() # 也可以写成下面这样:
    page2.click('//*[@id="localsearch"]')
    page2.wait_for_timeout(1000)
    if page2.locator('//*[@id="no_0"]/a').count() == 0:
      page2.wait_for_timeout(3000)
      page2.fill('//*[@id="localvalue"]', amp)
      page2.wait_for_timeout(1000)
      page2.click('//*[@id="localsearch"]')
      page2.wait_for_timeout(1000)
      if page2.locator('//*[@id="no_0"]/a').count() == 0:
        busi_data = [
        {
            "output_name": 'Unknow',
            "output_address": 'Unknow',
            "wgs84_lng": 'Unknow',
            "wgs84_lat": 'Unknow'
            }
        ]
        df = pd.DataFrame(busi_data)
        result2 = pd.concat([result2, df], axis=0, ignore_index=True)
        count += 1
        print(count,":",amp,"未能在地图中找到位置")
        return

    page2.click('//*[@id="no_0"]/a')
    page2.wait_for_timeout(1000)
    name = page2.query_selector('//*[@id="no_0"]/a').text_content()
    address = ((page2.query_selector('//*[@id="no_0"]/p').text_content()).split('      ')[0]).split(':')[1]
    lng = float(page2.query_selector('//*[@id="pointInput"]').input_value().split(",")[0])
    lat = float(page2.query_selector('//*[@id="pointInput"]').input_value().split(",")[1])
    wgs84_lng = round(llc.bd09_to_wgs84(lng,lat)[0],6)
    wgs84_lat = round(llc.bd09_to_wgs84(lng,lat)[1],6)
    busi_data = [
    {
        "output_name": name,
        "output_address": address,
        "wgs84_lng": wgs84_lng,
        "wgs84_lat": wgs84_lat
        }
    ]
    df = pd.DataFrame(busi_data)
    result2 = pd.concat([result2, df], axis=0, ignore_index=True)   # 将每次i结果union在一块(行方面追加)
    # 在 playwright 中有自带的延迟等待,单位是毫秒
    page2.wait_for_timeout(3000)  # 延迟关闭(为啥需要延迟一下,这里是用于测试,因为代码执行完马上就回关闭,运行太快了,还以为崩溃了
    
    

  # 遍历地址
  for i in range(len(name_list)):      
      get_poi_from_amap(region+name_list[i])
      print("进度:[",i+1,"/",len(name_list),"]", sep='')

  result1 = pd.concat([result1, result2], axis=1, ignore_index=True)  # 将社区名称和查询结果union在一块(列方面追加)
  result1.columns = ['name','facode','fname','output_name','output_address','wgs84_lng','wgs84_lat']
  # 将脚本所在路径作为excel输出路径
  output_path = os.getcwd() + os.sep + "output_region.xlsx"
  # 将结果写入到output_path 所在的excel中
  result1.to_excel(output_path, index=False)
  print("---------------经纬度获取完成(来源:百度地图)-------------------")
  print("有",count,"个地址未查询到对应的经纬度")
  # 使用完成关闭上下文(也就是会话窗口)
  content.close()

  # 关闭浏览器
  browser.close()


# 调用
with sync_playwright() as playwright:
  run(playwright)

3.convers.py:经纬度偏移转换

"""
  * 经纬度偏移转换
"""

import math
PI = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280
x_PI = float(PI * float(3000.0) / float(180.0))
aa = float(6378245.0)
ee = 0.00669342162296594323

def out_of_china(lng, lat):
    # 纬度3.86~53.55,经度73.66~135.05
    if 73.66 < lng < 135.05 and 3.86 < lat < 53.55:
        return False

def transform_lat(lng, lat):
    ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(lng))
    ret += (20.0 * math.sin(6.0 * lng * PI) + 20.0 * math.sin(2.0 * lng * PI)) * 2.0 / 3.0
    ret += (20.0 * math.sin(lat * PI) + 40.0 * math.sin(lat / 3.0 * PI)) * 2.0 / 3.0
    ret += (160.0 * math.sin(lat / 12.0 * PI) + 320 * math.sin(lat * PI / 30.0)) * 2.0 / 3.0
    return ret


def transform_lng(lng, lat):
    ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(lng))
    ret += (20.0 * math.sin(6.0 * lng * PI) + 20.0 * math.sin(2.0 * lng * PI)) * 2.0 / 3.0
    ret += (20.0 * math.sin(lng * PI) + 40.0 * math.sin(lng / 3.0 * PI)) * 2.0 / 3.0
    ret += (150.0 * math.sin(lng / 12.0 * PI) + 300.0 * math.sin(lng / 30.0 * PI)) * 2.0 / 3.0
    return ret

def bd09_to_gcj02(bd_lon, bd_lat):
    x = bd_lon - 0.0065
    y = bd_lat - 0.006
    z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * x_PI)
    theta = math.atan2(y, x) - 0.000003 * math.cos(x * x_PI)
    gg_lng = z * math.cos(theta)
    gg_lat = z * math.sin(theta)
    return [gg_lng, gg_lat]

def gcj02_to_wgs84(lng, lat):
    # 判断是否为国外坐标
    if out_of_china(lng, lat):
        return [lng, lat]
    else:
        dlat = transform_lat(lng - 105.0, lat - 35.0)
        dlng = transform_lng(lng - 105.0, lat - 35.0)
        radlat = lat / 180.0 * PI
        magic = math.sin(radlat)
        magic = 1 - ee * magic * magic
        sqrtmagic = math.sqrt(magic)
        dlat = (dlat * 180.0) / ((aa * (1 - ee)) / (magic * sqrtmagic) * PI)
        dlng = (dlng * 180.0) / (aa / sqrtmagic * math.cos(radlat) * PI)
        mglat = lat + dlat
        mglng = lng + dlng
        return [lng * 2 - mglng, lat * 2 - mglat]

def bd09_to_wgs84(lng, lat):
    point = bd09_to_gcj02(lng, lat)
    wgs84point = gcj02_to_wgs84(point[0], point[1])
    return [wgs84point[0], wgs84point[1]]

4.运行region.py文件

5.终端:查看进度

6.输出结果,在gis文件夹中会生成一个output_region.xlsx文件

name:社区名称

facode:所属街道区划代码

fname:所属街道名称

output_name:查询结果名称

output_address:查询结果地址

wgs84_lng:查询结果经度

wgs84_lat:查询结果纬度

问题汇总:

1)PermissionError: [Errno 13] Permission denied: 'E:\\gis\\output_region.xlsx'

说明output_region.xlsx文件未关闭,查询到的内容无法写入

2)开启无头浏览器

将region.py文件中的browser = playwright.chromium.launch(headless=False)修改为True

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值