关于爬取公交线路,网上一搜有很多,大部分都是从8684,图吧公交爬取数据,都能爬到相关线路,票价,时间,站点等信息,但是却无法爬取到站点的坐标信息,以及线路的坐标信息,但是这些坐标信息又是非常重要的,所以本文综合爬取8846和爬取高德地图站点信息坐标完成公交线路信息的获取。
说一下主要步骤
1.搭建scrapy框架
这个度娘一大堆,可以参考https://www.mscto.com/python/507221.html,https://blog.csdn.net/zjiang1994/article/details/52779537,https://blog.csdn.net/aibiabcheng/article/details/105525779等文章
2.爬取8648**市的公交线路
我们打开8648网站可以看到,8648里面包括所有公交线路的列表
我们通过解析html网页,获取到以数字开头和字母开头的所有公交线路,主要代码如下
a_list = response.xpath(
"//div[@class='bus-layer depth w120']/div[@class='pl10'][1]/div[@class='list']/a/@href").extract()
all_urls = [response.url + a.strip("/") for a in a_list] # url前缀列表
a_list2 = response.xpath(
"//div[@class='bus-layer depth w120']/div[@class='pl10'][2]/div[@class='list']/a/@href").extract()
all_urls2 = [response.url + a.strip("/") for a in a_list2] # url前缀列表
all_urls = all_urls+all_urls2
主要通过解析div的class获取到每个list的href再进行解析
获取到每个线路的链接后,我们再对每个线路的链接网页进行解析
这样的话,我们就得到所有的合肥市的公交线路
3.遍历每一条线路,再对每一条线路进行高德地图api请求,得到每一条线路的站点信息,票价信息,公司信息等,具体的可以参考文章https://zhuanlan.zhihu.com/p/141378209
url = 'https://restapi.amap.com/v3/bus/linename?s=rsv3&extensions=all&key=559bdffe35eec8c8f4dae959451d705c&output=json&city={}&offset=2&keywords={}&platform=JS'.format('合肥', line_name)来获得整个线路的信息,全部代码如下
import scrapy
from ..items import CityItem
from lxml import etree
import requests
import json
import re
import time
class BaiduSpider(scrapy.Spider):
name = 'busline'
start_urls = {
"https://{}.8684.cn/".format('hefei'),
}
def parse(self, response):
items = []
a_list = response.xpath(
"//div[@class='bus-layer depth w120']/div[@class='pl10'][1]/div[@class='list']/a/@href").extract()
all_urls = [response.url + a.strip("/") for a in a_list] # url前缀列表
a_list2 = response.xpath(
"//div[@class='bus-layer depth w120']/div[@class='pl10'][2]/div[@class='list']/a/@href").extract()
all_urls2 = [response.url + a.strip("/") for a in a_list2] # url前缀列表
all_urls = all_urls+all_urls2
for a in all_urls:
print(a)
tree = etree.HTML(requests.get(url=a).text)
detail_href = tree.xpath("//div[@class='list clearfix']/a/@href")
for detail in detail_href:
all_urls_1 = response.url + detail.strip("/")
tree = etree.HTML(requests.get(url=all_urls_1).text)
# 公交线路名称
line_name = tree.xpath("//div[@class='layout-left']/div[@class='bus-lzinfo mb20']//h1/text()")[0]
index = line_name.find('公交车路线')
line_name=line_name[2:index]
time.sleep(2)
#请求线路经过站点数据
url = 'https://restapi.amap.com/v3/bus/linename?s=rsv3&extensions=all&key=559bdffe35eec8c8f4dae959451d705c&output=json&city={}&offset=2&keywords={}&platform=JS'.format('合肥', line_name)
r = requests.get(url).text
rt = json.loads(r)
if rt['buslines']:
if len(rt['buslines']) == 0: # 有名称没数据
print(line_name+'没有数据!')
else:
#获取站点数据
for cc in range(len(rt['buslines'])):
up_down=cc
bus_setop = rt['buslines'][cc]["start_stop"]+"-"+rt['buslines'][cc]["end_stop"]
bus_cost = rt['buslines'][cc]["total_price"]
bus_type = rt['buslines'][cc]["type"]
bus_polyline = rt['buslines'][cc]["polyline"]
bus_company= rt['buslines'][cc]["company"]
for station_list in rt['buslines'][cc]['busstops']:
lineItem = CityItem()
lineItem["bus_name"] = line_name
#上下行
lineItem["bus_direction"] = up_down
# 起始点
lineItem["bus_setop"] = bus_setop
#站点
lineItem["bus_station"] = station_list["name"]
#坐标
lineItem["bus_location"] = station_list["location"]
#站点序号
lineItem["bus_sequence"] = station_list["sequence"]
#票价
lineItem["bus_cost"] = bus_cost
#类型
lineItem["bus_type"] = bus_type
#线路Polyline
lineItem["bus_polyline"] = bus_polyline
#所属公司
lineItem["bus_company"] = bus_company
print(lineItem)
items.append(lineItem)
return items
4.导出csv文件,在pipelines.py写入如下代码:
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
from scrapy.exporters import CsvItemExporter
import csv
import json
class FisrtpjPipeline:
def process_item(self, item, spider):
# 写入spider传过来的具体数值
self.writer.writerow(item)
# 写入完返回
return item
# 保存为csv格式
def __init__(self):
# 打开文件,指定方式为写,利用第3个参数把csv写数据时产生的空行消除
self.f = open("myproject.csv", "a", newline="")
# 设置文件第一行的字段名,注意要跟spider传过来的字典key名称相同
self.fieldnames = ["bus_name", "bus_direction", "bus_setop", "bus_station", "bus_location", "bus_sequence",
"bus_cost", "bus_type", "bus_polyline", "bus_company"]
# 指定文件的写入方式为csv字典写入,参数1为指定具体文件,参数2为指定字段名
self.writer = csv.DictWriter(self.f, fieldnames=self.fieldnames)
# 写入第一行字段名,因为只要写入一次,所以文件放在__init__里面
self.writer.writeheader()
def close(self, spider):
self.f.close()
5.配置好后,新建start.py写入如下代码
6.完成爬取后,我们开始csv文件,便得到了我们想要的数据
本文所有代码已上传github地址为https://github.com/wengjidong/ww2.git