「Python」爬虫实战-北京公交线路信息爬取(requests+bs4)

简介: 使用requests爬取北京公交线路信息,目标网址为[https://beijing.8684.cn/](https://beijing.8684.cn/)。爬取的具体信息为公交线路名称、公交的运营范围、运行时间、参考票价、公交所属的公司以及服务热线、公交来回线路的途径站点。

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天, 点击查看活动详情

公交线路爬取

使用requests爬取北京公交线路信息,目标网址为https://beijing.8684.cn/

爬取的具体信息为公交线路名称、公交的运营范围、运行时间、参考票价、公交所属的公司以及服务热线、公交来回线路的途径站点。

考虑到现代技术与日俱进,反爬措施层数不穷,故可以考虑构建用户代理池,能够避免总是使用一个 UA 来访问网站,因为短时间内总使用一个 UA 高频率访问的网站,可能会引起网站的警觉,从而封杀掉 IP。

这里对User Agent的构造进行分析。标准的UA是由浏览器标识 (操作系统标识; 加密等级标识; 浏览器语言) 、渲染引擎标识、 版本信息组成,所以不妨采用构造UA的方法结合随机函数,随机生成一个UA,以达到混淆服务器的效果。
核心部分代码如下:

def get_ua():
    first_num = random.randint(55, 76)
    third_num = random.randint(0, 3800)
    fourth_num = random.randint(0, 140)
    os_type = [
        '(Windows NT 6.1; WOW64)', '(Windows NT 10.0; WOW64)', 
        '(X11; Linux x86_64)', '(Macintosh; Intel Mac OS X 10_14_5)'
    ]
    chrome_version = 'Chrome/{}.0.{}.{}'.format(first_num, third_num, fourth_num)

    ua = ' '.join(['Mozilla/5.0', random.choice(os_type), 'AppleWebKit/537.36',
                   '(KHTML, like Gecko)', chrome_version, 'Safari/537.36']
                 )
    return ua

观察到目标网站的公交线路分别有以1开头至9开头以及url的变化。不难看出,以什么开头的公交就在https://beijing.8684.cn/ 后面加上list?。若以字母B开头,则为listB。通过字符串的拼接就可以得到不同数字或字母开头的公交线路名称。
image.pngimage.png
F12键观察一下页面的元素排列,通过观察页面源代码发现,我们所看到的代码与页面源代码没有出入(有些在页面源代码中并没有渲染信息在HTML中,而是通过js渲染到浏览器中)。
image.png

下面以1路车为例,进入到公交线路信息详情的页面进行信息提取。
image.png
观察页面发现1路公交车的详情页面 -> https://beijing.8684.cn/x_322e21c5 的url的最后的参数刚好和 https://beijing.8684.cn/list1 页面中的 a标签的href属性对应起来。

所以大胆假设:每一个list页面中相同位置的a标签的属性href中的值就是相应的线路详情路线的后缀,所以每个线路的具体目标网址只需要拿到list页面中的href值,然后和https://beijing.8684.cn/ 拼接就可得到线路的url

对于公交线路的名称、运行时间、所属区域、参考票价以及所属公司在页面中的位置都是在div class="info"的盒子里,并且发现class="info"的属性值在整个页面中只出现了一次。通过get_text()方法就可以提取到所需要的信息。

而对于公交来回具体经过的地方,在页面渲染时,由于经过的站太多,在页面需要隐藏显示,所以直接找到站点对应的div并提取text时,会提取到一些不需要的信息。在获取到信息还需要根据实际情况处理掉冗余的信息,保证爬取信息的正确性。

由于目标网站对于每个页面的渲染可能存在不同,也可能笔者在提取需要的信息考虑不完全等原因,并不能完全保证每一个页面都能完整的提取到所需要的信息。
故需要利用到try...except...来捕捉异常将不符合提取信息逻辑的页面的url另存一个文件,并在信息爬取结束后,观察该页面,进而完善原有代码或者模块。

运行效果

信息爬取成功界面:
image.png
爬取的信息:
image.png

注意到error文件中的链接只有一个,说明前面的逻辑还是写的相当不错的,😀囊括了大部分的情况,能够爬取到目标信息。

具体代码

from bs4 import BeautifulSoup
import requests
import random

# UA池
def get_headers(referer_url):
    first_num = random.randint(55, 76)
    third_num = random.randint(0, 3800)
    fourth_num = random.randint(0, 140)
    os_type = [
        '(Windows NT 6.1; WOW64)', '(Windows NT 10.0; WOW64)', '(X11; Linux x86_64)',
        '(Macintosh; Intel Mac OS X 10_14_5)'
    ]
    chrome_version = 'Chrome/{}.0.{}.{}'.format(first_num, third_num, fourth_num)

    ua = ' '.join(['Mozilla/5.0', random.choice(os_type), 'AppleWebKit/537.36',
                   '(KHTML, like Gecko)', chrome_version, 'Safari/537.36']
                  )
    headers = {
        "User-Agent": ua,
        "Referer": referer_url
    }
    return headers


def main():
    url = 'https://beijing.8684.cn'

    # bus_head = [str(i) for i in range(1, 10)] + ['B', 'C', 'D', 'F']

    bus_head = [str(i) for i in range(1, 3)]

    for bus in bus_head:
        bus_single_url = url + '/list' + bus  # 1字开头的bus
        resp = requests.get(bus_single_url, headers=get_headers(url))
        bus_main_html = BeautifulSoup(resp.text, 'html.parser')

        bus_route_list = bus_main_html.find('div', class_="list clearfix").find_all('a')
        route_href = []  # 只存取线路的链接-/x_322e21c5, 完整的url需要拼接  
        # 即:url + route_href[0] = https://beijing.8684.cn/x_322e21c5
        for single_route in bus_route_list:
            route_href.append(single_route.get('href'))

        for href in route_href:
            route_url = url + href

            bus_detail = requests.get(route_url, headers=get_headers(bus_single_url))

            bus_detail_html = BeautifulSoup(bus_detail.text, 'html.parser')

            try:
                bus_info = bus_detail_html.find('div', class_="info")

                detail = bus_info.get_text('#').split('#')[:6]

                route_total = bus_detail_html.find_all('div', 'bus-excerpt mb15')
                bus_lzlist = bus_detail_html.find_all('div', 'bus-lzlist mb15')

                with open('bus.txt', 'a') as f:
                    f.write('\n')
                    f.write('\n'.join(detail[:4]))  # 只需要写入一次
                    f.write('\n' + detail[-2] + detail[-1])  # 公司名

                for route, bus_ls in zip(route_total, bus_lzlist):
                    trip = route.find('div', 'trip').get_text()
                    start, end = trip.split('—')  # 获取起始站点和终点站的名字
                    li_list = [li.get_text() for li in bus_ls.find_all('a')]  # 获取经过站点
                    tmp = [li for idx, li in enumerate(li_list[1:-1]) if li != start and li != end] # 去掉首尾两个站点
                    tmp = [li_list[0]] + tmp + [li_list[-1]]  # 加上起始站点和终点站
                    tmp = [f'{idx + 1}:{r}' for idx, r in enumerate(tmp)]  # 添加站点编号
                    with open('bus.txt', 'a') as f:
                        f.write('\n' + trip + '\n')
                        f.write('->'.join(tmp))
                print(f'{route_url}信息写入成功!')
            except:
                with open('error.txt', 'a') as f:  # 爬取不到的路线,在细致分析
                    f.write(route_url + '\n')


if __name__ == '__main__':
    main()
一些心得:

在提取详情站点信息的时候由于最终写入的文本站点信息不能重复,即公交的起始点和终点只能出现一次,但是在直接使用get_text()方法时,或获取到多余的站点,即终点站的名称出现了两次。

解决方法:
对获取到的站点列表的中间部分(即去除了起始点和终点的部分)进行遍历,若当前的值是终点站或者起始站,则将该值从列表中删除。

相关文章
|
1月前
|
数据采集 存储 XML
Python爬虫:深入探索1688关键词接口获取之道
在数字化经济中,数据尤其在电商领域的价值日益凸显。1688作为中国领先的B2B平台,其关键词接口对商家至关重要。本文介绍如何通过Python爬虫技术,合法合规地获取1688关键词接口,助力商家洞察市场趋势,优化营销策略。
|
6天前
|
数据采集 供应链 API
Python爬虫与1688图片搜索API接口:深度解析与显著收益
在电子商务领域,数据是驱动业务决策的核心。阿里巴巴旗下的1688平台作为全球领先的B2B市场,提供了丰富的API接口,特别是图片搜索API(`item_search_img`),允许开发者通过上传图片搜索相似商品。本文介绍如何结合Python爬虫技术高效利用该接口,提升搜索效率和用户体验,助力企业实现自动化商品搜索、库存管理优化、竞品监控与定价策略调整等,显著提高运营效率和市场竞争力。
30 3
|
17天前
|
数据采集 存储 缓存
如何使用缓存技术提升Python爬虫效率
如何使用缓存技术提升Python爬虫效率
|
18天前
|
数据采集 Web App开发 监控
Python爬虫:爱奇艺榜单数据的实时监控
Python爬虫:爱奇艺榜单数据的实时监控
|
27天前
|
数据采集 JSON API
如何利用Python爬虫淘宝商品详情高级版(item_get_pro)API接口及返回值解析说明
本文介绍了如何利用Python爬虫技术调用淘宝商品详情高级版API接口(item_get_pro),获取商品的详细信息,包括标题、价格、销量等。文章涵盖了环境准备、API权限申请、请求构建和返回值解析等内容,强调了数据获取的合规性和安全性。
|
1月前
|
数据采集 存储 API
利用Python爬虫获取1688关键词接口全攻略
本文介绍如何使用Python爬虫技术合法合规地获取1688关键词接口数据,包括环境准备、注册1688开发者账号、获取Access Token、构建请求URL、发送API请求、解析HTML及数据处理存储等步骤,强调遵守法律法规和合理使用爬虫技术的重要性。
|
1月前
|
数据采集 JSON 开发者
Python爬虫京东商品详情数据接口
京东商品详情数据接口(JD.item_get)提供商品标题、价格、品牌、规格、图片等详细信息,适用于电商数据分析、竞品分析等。开发者需先注册账号、创建应用并申请接口权限,使用时需遵循相关规则,注意数据更新频率和错误处理。示例代码展示了如何通过 Python 调用此接口并处理返回的 JSON 数据。
|
2月前
|
数据采集 存储 JSON
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第27天】本文介绍了Python网络爬虫Scrapy框架的实战应用与技巧。首先讲解了如何创建Scrapy项目、定义爬虫、处理JSON响应、设置User-Agent和代理,以及存储爬取的数据。通过具体示例,帮助读者掌握Scrapy的核心功能和使用方法,提升数据采集效率。
130 6
|
5月前
|
机器学习/深度学习 数据采集 数据可视化
基于爬虫和机器学习的招聘数据分析与可视化系统,python django框架,前端bootstrap,机器学习有八种带有可视化大屏和后台
本文介绍了一个基于Python Django框架和Bootstrap前端技术,集成了机器学习算法和数据可视化的招聘数据分析与可视化系统,该系统通过爬虫技术获取职位信息,并使用多种机器学习模型进行薪资预测、职位匹配和趋势分析,提供了一个直观的可视化大屏和后台管理系统,以优化招聘策略并提升决策质量。
273 4
|
6月前
|
数据采集 存储 JSON
从零到一构建网络爬虫帝国:HTTP协议+Python requests库深度解析
【7月更文挑战第31天】在网络数据的海洋中,使用Python的`requests`库构建网络爬虫就像探索未知的航船。HTTP协议指导爬虫与服务器交流,收集信息。HTTP请求包括请求行、头和体,响应则含状态行、头和体。`requests`简化了发送各种HTTP请求的过程。
105 4