Crawler爬取旅行轨迹数据 - 以两步路官网为例

在这里插入图片描述

在这个示例中,我们将演示如何爬取湖北武汉东湖的旅行轨迹数据。请注意,这只是一个示例,您可以根据自己的需求来修改爬虫设置。

步骤 1: 查找所需信息

1.1 依据网页,查找所需信息

首先,打开浏览器并访问两步路官网。然后,使用开发者工具,切换到 “网络” 或 “Network” 选项卡,并选择 “XHR”。在这里,我们发现网页只有4条数据。逐条查找这些请求,以确定预览的网页中的内容包含了我们所需的旅行轨迹数据。从中确定目标网页名称。

1.2 确定网页正式访问的URL

在开发者工具的 “标头” 栏中,查找网页正式访问的URL链接,这将是我们在爬虫中使用的链接。

在这里插入图片描述

1.3 确定爬取的设定参数

在开发者工具的 “负载” 栏中,查找网页爬取的设定参数,这些参数在后续爬虫代码中需要使用。

步骤 2: 访问网页内容

根据上述确定的正式URL链接和设定参数,创建Python代码来访问网页内容。示例代码如下:

def send_http_post_request(url, page_number):
    """
    发送HTTP POST请求并获取数据。

    :param url: 目标URL
    :param page_number: 页码
    :return: 请求响应的文本内容,如果请求失败则返回None
    """
    # 设置请求头
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.43'

    }

    # 构建请求参数
    data = {
        'pageNumber': page_number,
        'sortType': 0,
        'areaId': '15728',
        'parentId': '15727',
    }

    # 设置请求的cookie信息
    cookies = {}
    co_data = '你的cookies '
    for i in co_data.split('; '):
        cookies[i.split('=')[0]] = i.split('=')[1]

    try:
        # 发送POST请求
        response = requests.post(url=url, headers=headers, cookies=cookies, data=data, timeout=10)

        # 检查响应状态码
        if response.status_code == 200:
            return response.text
        else:
            print(f"Failed to fetch data for page {page_number}. Status code: {response.status_code}")
            return None
    except requests.exceptions.RequestException as e:
        print(f"Error while fetching data for page {page_number}: {e}")
        return None

步骤 3: 提取有效信息

代码中使用了Beautiful Soup的各种方法来定位、提取和处理HTML中的特定元素和文本内容,以构建包含所需数据的列表。以下是一个示例,提取的信息包括目标链接、轨迹名称、出行方式、里程、用户名称、上传时间、行程安排、点赞、下载和收藏。

def parse_html_data(page, data):
    """
    解析HTML数据,提取所需信息并存储到列表中。

    :param data: HTML文本数据
    :return: 存储解析数据的列表
    """
    page_counter = 1
    parsed_data = []
    soup = BeautifulSoup(data, "html.parser")
    target_divs = soup.find_all('div', class_='guiji_discription')

    for target_div in target_divs:
        # 构建轨迹id
        trajectory_id = (page - 1) * 10 + page_counter

        # 构建轨迹URL
        url_link_1 = 'https://www.2bulu.com'
        url_link_2 = target_div.find('a')['href']
        target_url = url_link_1 + url_link_2

        # 查找轨迹名称
        target_p = target_div.find('p', class_='guiji_name').get_text()
        text_list = [item.strip() for item in target_p.split('\n') if item.strip()]
        trajectory_name = text_list[-1]

        # 查找骑行方式
        original_travel_mode = target_div.find('p', class_='guiji_name').span.get_text().strip()
        travel_mode = re.sub(r'[^\u4e00-\u9fa5]+', '', original_travel_mode)

        # 查找里程数
        original_mileage = target_div.find('span', class_='s1').get_text(strip=True)
        mileage = [item.strip() for item in original_mileage.split('\n')][0]

        # 查找作者
        user_name = target_div.find('span', class_='s7').a.get_text(strip=True)

        # 查找上传时间
        original_upload_time = target_div.find('span', class_='s7').get_text()
        upload_time = [item.strip() for item in original_upload_time.split('\n') if item.strip()][-1]

        # 查找行程
        original_itinerary = target_div.find_all('li')[1].get_text(strip=True)
        itinerary = re.sub(r'\s+', '', original_itinerary)

        # 查找点赞数
        original_like = target_div.find('span', class_='s3').get_text(strip=True)
        like = re.findall(r'\d+\.\d+|\d+', original_like)[0]

        # 查找下载数
        original_download = target_div.find('span', class_='s4').get_text(strip=True)
        download = re.findall(r'\d+\.\d+|\d+', original_download)[0]

        # 查找收藏数
        original_bookmark = target_div.find('span', class_='s5').get_text(strip=True)
        bookmark = re.findall(r'\d+\.\d+|\d+', original_bookmark)[0]

        # 构建临时列表,存储每条轨迹的数据
        temporary_list = [trajectory_id, target_url, trajectory

_name, travel_mode, mileage, user_name, upload_time,
                          itinerary,
                          like, download, bookmark]


        parsed_data.append(temporary_list)

        page_counter += 1
        print(temporary_list)

    return parsed_data

步骤 4: 解决登录校验的问题

如果您需要爬取多个页面或需要登录后的Cookie来继续爬取,在已经登录的网站中找到网页的cookie通常需要使用浏览器的开发者工具。您可以按照下面步骤来获取所需的Cookie信息。

  1. 使用浏览器登录
    首先,使用您的浏览器登录到目标网站。确保您已经登录成功并可以访问需要的页面。

  2. 打开开发者工具
    打开浏览器的开发者工具。不同浏览器的打开方式略有不同,通常可以通过按下F12键或Ctrl + Shift + I(在Windows/Linux系统下)或Cmd + Option + I(在Mac系统下)来打开开发者工具。

  3. 选择选项卡
    在开发者工具中,通常有一个名为"XHR"的选项卡(具体名称可能会因浏览器而异),请点击它。

  4. 查看Cookie
    在选项卡目标网页的“表头”中,可以找到"Cookie"或"Cookies"。

步骤 5: 整体代码

整体代码如下所示:

import re
import csv
import time
import random
import requests
from bs4 import BeautifulSoup


def send_http_post_request(url, page_number):
    """
    发送HTTP POST请求并获取数据。

    :param url: 目标URL
    :param page_number: 页码
    :return: 请求响应的文本内容,如果请求失败则返回None
    """
    # 设置请求头
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.43'

    }

    # 构建请求参数
    data = {
        'pageNumber': page_number,
        'sortType': 2,
        'trackType': 8,  # 步行
        # 'trackType': 2,  # 骑行
        'areaId': '15728',
        'parentId': '15727',
    }

    # 设置请求的cookie信息
    cookies = {}
    co_data = '…JSESSIONID=5F93F98CB090214EA8B1E93BA41E4DB6-n1; …'
    for i in co_data.split('; '):
        cookies[i.split('=')[0]] = i.split('=')[1]

    try:
        # 发送POST请求
        response = requests.post(url=url, headers=headers, cookies=cookies, data=data, timeout=10)

        # 检查响应状态码
        if response.status_code == 200:
            return response.text
        else:
            print(f"Failed to fetch data for page {page_number}. Status code: {response.status_code}")
            return None
    except Exception as e:
        print(f"Error while fetching data for page {page_number}: {e}")
        return None


def parse_html_data(page, data):
    """
    解析HTML数据,提取所需信息并存储到列表中。

    :param data: HTML文本数据
    :return: 存储解析数据的列表
    """
    page_counter = 1
    parsed_data = []
    soup = BeautifulSoup(data, "html.parser")
    target_divs = soup.find_all('div', class_='guiji_discription')

    for target_div in target_divs:
        # 构建轨迹id
        trajectory_id = (page - 1) * 10 + page_counter

        # 构建轨迹URL
        url_link_1 = 'https://www.2bulu.com'
        url_link_2 = target_div.find('a')['href']
        target_url = url_link_1 + url_link_2

        # 查找轨迹名称
        target_p = target_div.find('p', class_='guiji_name').get_text()
        text_list = [item.strip() for item in target_p.split('\n') if item.strip()]
        trajectory_name = text_list[-1]

        # 查找骑行方式
        original_travel_mode = target_div.find('p', class_='guiji_name').span.get_text().strip()
        travel_mode = re.sub(r'[^\u4e00-\u9fa5]+', '', original_travel_mode)

        # 查找里程数
        original_mileage = target_div.find('span', class_='s1').get_text(strip=True)
        mileage = [item.strip() for item in original_mileage.split('\n')][0]

        # 查找作者
        user_name = target_div.find('span', class_='s7').a.get_text(strip=True)

        # 查找上传时间
        original_upload_time = target_div.find('span', class_='s7').get_text()
        upload_time = [item.strip() for item in original_upload_time.split('\n') if item.strip()][-1]

        # 查找行程
        original_itinerary = target_div.find_all('li')[1].get_text(strip=True)
        itinerary = re.sub(r'\s+', '', original_itinerary)

        # 查找点赞数
        original_like = target_div.find('span', class_='s3').get_text(strip=True)
        like = re.findall(r'\d+\.\d+|\d+', original_like)[0]

        # 查找下载数
        original_download = target_div.find('span', class_='s4').get_text(strip=True)
        download = re.findall(r'\d+\.\d+|\d+', original_download)[0]

        # 查找收藏数
        original_bookmark = target_div.find('span', class_='s5').get_text(strip=True)
        bookmark = re.findall(r'\d+\.\d+|\d+', original_bookmark)[0]

        # 构建临时列表,存储每条轨迹的数据
        temporary_list = [trajectory_id, target_url, trajectory_name, travel_mode, mileage, user_name, upload_time,
                          itinerary,
                          like, download, bookmark]
        parsed_data.append(temporary_list)

        page_counter += 1
        print(temporary_list)

    return parsed_data


def write_data_to_csv(csv_path, header, data):
    """
    将数据列表写入CSV文件。

    :param csv_path: CSV文件路径
    :param header: CSV文件的列标题
    :param data: 要写入CSV的数据列表
    """
    with open(csv_path, 'w', encoding='utf-8-sig', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(header)
        writer.writerows(data)


def random_delay(min_delay, max_delay):
    """
    随机延时函数,生成指定范围内的随机延时时间。

    :param min_delay: 最小延时(秒)
    :param max_delay: 最大延时(秒)
    """
    delay = random.uniform(min_delay, max_delay)
    time.sleep(delay)


def main():
    url = 'https://www.2bulu.com/track/track_search_result.htm'
    csv_header = ['trajectory_id', 'target_url', 'trajectory_name',
                  'travel_mode', 'mileage', 'user_name', 'upload_time', 'itinerary',
                  'like', 'download', 'bookmark']
    parsed_data = []
    start_page = 1
    end_page = 5  # 增加了一个示例值,可以根据需求更改

    for page_number in range(start_page, end_page + 1):
        data = send_http_post_request(url=url, page_number=page_number)
        if len(data) <= 150:
            time.sleep(120)
        parsed_data.extend(parse_html_data(page=page_number, data=data))
        # 随机访问时间,反爬
        random_delay(min_delay=5, max_delay=10)

    csv_file_path = str(start_page) + '_' + str(int(parsed_data[-1][0] / 10)) + "_output.csv"
    write_data_to_csv(csv_path=csv_file_path, header=csv_header, data=parsed_data)
    print('CSV导出完成。')


if __name__ == "__main__":
    main()

这是一个完整的示例,演示了如何爬取湖北武汉东湖的旅行轨迹数据。请根据您的实际需求和网站结构进行适当的修改和扩展。

计算机术语和函数解释表格

术语/函数解释
HTTP POST请求发送HTTP POST请求并获取数据。
BeautifulSoup用于解析HTML数据,提取所需信息的Python库。
requests用于发送HTTP请求的Python库。
cookies存储在浏览器中的网站数据,通常用于身份验证和状态跟踪。
User-AgentHTTP请求头中的字段,标识客户端应用程序的类型和版本。
rePython的正则表达式库,用于文本匹配和处理。
page_number页码,用于指示要爬取的页面编号。
URL链接统一资源定位符,用于标识互联网上的资源位置。

如果这对您有所帮助,希望点赞支持一下作者! 😊

点击查看原文

file

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值