Scrapy 爬取旅游景点相关数据(三)

news2024/12/27 13:45:21
  • 这一节我们将之前爬取到的景点数据进行解析,并且保存为excel,便于后续使用,本节包含

    (1) 景点数据解析

    (2)数据保存到excel

1 编写爬虫

这次继续改进第二节的爬虫,新建一个爬虫文件叫 spiders/qiongyou_3.py

因为这一节开始我们直接解析返回的response了,所以不需要保存html了。

编写一个自定义程序去解析页面的源码提取我们需要的信息

        while True:
            # 先爬取3页 (测试)
            if page_number > 3:
                break

            # 解析当前页面内容(如果需要解析,可以在这里添加解析逻辑)
            page_source = self.driver.page_source
            for item in self.parse_page(page_source):
                yield item

parse_page方法这样写

# 解析页面
    def parse_page(self, page_source):
        response = scrapy.Selector(text=page_source)
        print(response)
        sights = response.xpath('//ul[@id="poiLists"]/li')
        print('sights=', sights)
        for sight in sights:
            item = TourItem()
            item['title'] = sight.xpath('.//h3[@class="title fontYaHei"]/a/text()').get().strip()
            item['title_en'] = (sight.xpath('.//h3[@class="title fontYaHei"]/a/span/text()').get() or '').strip()
           
            print(f"\033[92m{item['title']}\033[0m")
            print(f"\033[92m{item['title_en']}\033[0m")
        
            yield item

先打通流程,所以只提取2个字段,景点中文名和英文名

这边title_en这么写的原因是景点的外文名可能是不存在的,如果不加处理地提取会报错导致程序直接中断。

2 修改 items

修改items.py ,定义我们自己的数据结构

# 定义数据结构
class TourItem(scrapy.Item):
    title = scrapy.Field()
    title_en = scrapy.Field()

3 修改 Pipelines

利用pipelines 来对数据进行保存。

import pandas as pd

class TourPipeline:
    def __init__(self):
        self.data = []

    def process_item(self, item, spider):
        self.data.append(dict(item))
        return item

    def close_spider(self, spider):
        df = pd.DataFrame(self.data)
        # 使用pandas 保存东京景点 到excel文件
        df.to_excel('tokyo_sights.xlsx', index=False)
        spider.log('Saved data to tokyo_sights.xlsx')

需要安装pandas。

pip install pandas

还需要在settings.py 中打开配置。

ITEM_PIPELINES = {
   'tutorial2.pipelines.TourPipeline': 300,
}

4 执行代码

scrapy crawl qys3 

在测试的时候发现,第一次调的时候,通常驱动启动的会比较慢(这个原因我们下一期说),而后面调试就很快,发现数据可以保存到excel 。

5 完整qiongyou_3.py代码 & items.py 代码

后续继续解析其他字段,这边就直接贴出代码。

# qiongyou_3.py
import re
import scrapy
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium import webdriver
from selenium.webdriver.remote.remote_connection import LOGGER
import logging
import time

from tutorial2.items import TourItem

class QiongyouSpider(scrapy.Spider):
    name = 'qys3'
    allowed_domains = ['qyer.com']
    start_urls = ['https://place.qyer.com/tokyo/sight/']

    def __init__(self, *args, **kwargs):
        super(QiongyouSpider, self).__init__(*args, **kwargs)
        options = webdriver.ChromeOptions()
        options.add_argument('--headless')
        LOGGER.setLevel(logging.WARNING)

        self.driver = webdriver.Chrome(options=options)  # 替换为 ChromeDriver 的实际路径

    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        # 定义对网站的操作(保存HTML)
        self.driver.get(response.url)
        # 等待页面加载
        WebDriverWait(self.driver, 10).until(
            EC.presence_of_element_located((By.XPATH, '//ul[@id="poiLists"]'))
        )

        page_number = 1
        while True:
            # 先爬取3页 (测试)
            if page_number > 40:
                break

            # 解析当前页面内容(如果需要解析,可以在这里添加解析逻辑)
            page_source = self.driver.page_source
            for item in self.parse_page(page_source):
                yield item

            # 查找并点击 "下一页" 按钮
            try:
                # javascript
                next_button = self.driver.find_element(By.XPATH, '//a[@title="下一页"]')
                self.driver.execute_script("arguments[0].click();", next_button)

                page_number += 1
                time.sleep(2)  # 等待页面加载
                WebDriverWait(self.driver, 10).until(
                    EC.presence_of_element_located((By.XPATH, '//ul[@id="poiLists"]'))
                )
            except Exception as e:
                self.log(f"No more pages or failed to load next page: {e}")
                break

        self.driver.quit()

    # 解析页面
    def parse_page(self, page_source):
        response = scrapy.Selector(text=page_source)
        print(response)
        sights = response.xpath('//ul[@id="poiLists"]/li')
        print('sights=', sights)
        for sight in sights:
            item = TourItem()
            item['title'] = sight.xpath('.//h3[@class="title fontYaHei"]/a/text()').get().strip()
            item['title_en'] = (sight.xpath('.//h3[@class="title fontYaHei"]/a/span/text()').get() or '').strip()
            item['img'] = (sight.xpath('.//p[@class="pics"]/a/img/@src').get() or '').strip()
            item['score'] = (sight.xpath('.//div[@class="info"]/span[@class="grade"]/text()').get() or '').strip()
            comment = (sight.xpath('.//span[@class="dping"]/a/text()').get() or '').strip()
            item['comment_url'] = 'https:' + (sight.xpath('.//span[@class="dping"]/a/@href').get() or '').strip()
            item['rank_title'] = (sight.xpath('.//div[@class="info"]//span[@class="infoSide"]/text()').get() or '').strip()

            item['select_user'] = (sight.xpath('.//p[@class="user"]/a/img/@src').get() or '').strip()
            item['select_comment'] = (sight.xpath('.//div[@class="txt"]/text() | .//p[@class="txt"]/text()').get() or '').strip()

            rank = (sight.xpath('.//div[@class="info"]//em[@class="rank orange"]/text()').get() or '').strip()

            review_count_pattern = r'(\d+)人点评'
            review_count_match = re.search(review_count_pattern, comment)
            if review_count_match:
                item['comment'] = int(review_count_match.group(1))
            else:
                item['comment'] = 0

            rank_pattern = r'第(\d+)位'
            rank_match = re.search(rank_pattern, rank)
            if rank_match:
                item['rank'] = int(rank_match.group(1))
            else:
                item['rank'] = 0

            print(f"\033[92m{item['title']}\033[0m")
            print(f"\033[92m{item['title_en']}\033[0m")
            print(f"\033[92m{item['img']}\033[0m")
            print(f"\033[92m{item['score']}\033[0m")
            print(f"\033[92m{item['comment_url']}\033[0m")

            print(f"\033[92m{item['comment']}\033[0m")
            print(f"\033[92m{item['rank_title']}\033[0m")
            print(f"\033[92m{item['rank']}\033[0m")

            print(f"\033[92m{item['select_user']}\033[0m")
            print(f"\033[92m{item['select_comment']}\033[0m")

            yield item

# items.py

import scrapy

# 定义数据结构
class TourItem(scrapy.Item):
    title = scrapy.Field()
    title_en = scrapy.Field()
    img = scrapy.Field()
    score = scrapy.Field()
    comment = scrapy.Field()
    comment_url = scrapy.Field()
    rank_title = scrapy.Field()
    rank = scrapy.Field()
    select_user = scrapy.Field()
    select_comment = scrapy.Field()

最后爬取到的excel 效果:
在这里插入图片描述

下一期我们就把数据存储到mysql中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1951373.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#如何引用dll动态链接库文件的注释

1、dll动态库文件项目生成属性中要勾选“XML文档文件” 注意:XML文件的名字切勿修改。 2、添加引用时XML文件要与DLL文件在同一个目录下。 3、如果要是添加引用的时候XML不在相同目录下,之后又将XML文件复制到相同的目录下,需要删除引用&am…

蓝桥强化宝典(3)BFS

一、定义 广度优先搜索(Breadth-First Search, BFS)是另一种用于遍历或搜索树或图的算法。与深度优先搜索(DFS)沿着树的深度遍历不同,广度优先搜索会逐层遍历图的顶点。它从一个指定的源顶点开始,首先访问这…

失业潮下,有人靠天工AI做副业年入10万?

前言 你好,我是咪咪酱 这篇文章总结2个AI副业项目,不用写代码,就能做的2个副业项目。 第一:AI生成微信表情包,上传到微信表情包平台等,坚持下去,会有可观的收入。 第二:AI生成连载…

Java 8 中 20 个高频面试题及答案

文章目录 前言20 道高频题问题 1:给定一个整数列表,使用 Stream 函数找出列表中所有的偶数?问题 2:给定一个整数列表,使用 Stream 函数找出所有以 1 开头的数字?问题 3:如何使用 Stream 函数在给…

1.ESP32-CAM 下使用 ESP-IDF 打开摄像头

主要资料: 乐鑫官方编程指南 ESP-IDF 编程指南安信可官方模块页 安信可-ESP32-CAM摄像头开发板官方使用教程 安信可ESP32-CAM摄像头开发demo–局域网拍照、实时视频、人脸识别 (开发环境是Linux) 本文目标是在 Windows 下跑通摄像头 hello …

国衍科技——RFID技术的应用

在文物馆藏信息的记录与管理过程中,准确性和详细性是至关重要的。无论是大型博物馆还是私人收藏馆,都需要有效的方法来确保馆藏文物信息的可追溯性和可访问性,才能提供更好的服务和保护馆藏资源。而结合射频识别(RFID)…

2-46 基于matlab的声音信号的短时能量、短时过零率、端点检测

基于matlab的声音信号的短时能量、短时过零率、端点检测。通过计算计算短时能量、调整能量门限,然后开始端点检测。输出可视化结果。程序已调通,可直接运行。 2-46 短时能量 短时过零率 端点检测 - 小红书 (xiaohongshu.com)

未来的智能农业:智能合约如何提升农业生产效率和可持续性

随着全球人口的增长和资源的有限性,农业生产面临着越来越大的挑战。如何在提高生产效率的同时保障可持续发展成为全球农业发展的关键问题。智能合约作为一种基于区块链技术的自动化执行合约,正在逐渐应用于农业领域,为农业生产带来了新的机遇…

【MATLAB源码-第238期】基于simulink的三输出单端反激flyback仿真,通过PWM和PID控制能够得到稳定电压。

操作环境: MATLAB 2022a 1、算法描述 概述 反激变换器是一种广泛应用于电源管理的拓扑结构,特别是在需要隔离输入和输出的应用中。它的工作原理是利用变压器的储能和释放能量来实现电压转换和隔离。该图展示了一个通过脉宽调制(PWM&#…

C++——QT:保姆级教程,从下载到安装到用QT写出第一个程序

登录官网,在官网选择合适的qt版本进行下载 这里选择5.12.9版本 点击exe文件下载,因为服务器在国外,国内不支持,所以可以从我的网盘下载 链接: https://pan.baidu.com/s/1XMILFS1uHTenH3mH_VlPLw 提取码: 1567 --来自百度网盘超级…

git merge VS git rebase VS git cherry-pick

git merge VS git rebase VS git cherry-pick 在Git中,git merge、git rebase和git cherry-pick都是用于整合不同分支中的更改到当前分支的命令。它们各有特点和适用场景。 Git Merge git merge 是一种将一个分支的更改合并到另一个分支的方法。它创建一个新的提…

用Postman Flows打造你的专属API:外部公开,轻松上手!

引言 Postman Flows 是一个使用 GUI 进行无代码 API 调用流程创建的服务。这篇文章我尝试使用 Flows 来构建将 Momento Topic 中的数据保存到 TiDB 的保存 API,因此想分享一些使用过程中的技巧等。 实现内容 将从 Momento Topics 配发的 JSON 数据保存到 TiDB 中。…

算法-BFS搜索

题目一 解题思路 比较标准的暴力搜索空间换时间的策略 二维数组map表示具体地图,far表示遍历过程中某点到起点的距离。 队列 q 表示在遍历过程中当前距离的所以节点坐标。 每次的节点寻找其上下左右四个方向可以继续前进的点(这里在过程中会发生两个…

Java之多线程-同步代码块

线程同步 Java中提供了线程同步的机制,来解决上述的线程安全问题。 Java中实现线程同步,主要借助synchronized关键字实现。 线程同步方式: 同步代码块 同步方法 锁机制 1)同步代码块 格式: //Object类及其子类…

Web网页端IM产品RainbowChat-Web的v7.1版已发布

一、关于RainbowChat-Web RainbowChat-Web是一套Web网页端IM系统,是RainbowChat的姊妹系统(RainbowChat是一套基于开源IM聊天框架 MobileIMSDK (Github地址) 的产品级移动端IM系统)。 ► 详细介绍:http://www.52im.net/thread-2…

研发(RD)注意事项 / 复杂项目规划、控制方法 PERT 和 CPM

注:机翻,未校对,去掉了原文中广告。 What Is Research and Development (R&D)? 什么是研发(R&D)? Investopedia / Ellen Lindner Research and Development An ongoing effort to develop or impr…

Spring Boot入门指南:留言板

一.留言板 1.输⼊留⾔信息,点击提交.后端把数据存储起来. 2.⻚⾯展⽰输⼊的表⽩墙的信息 规范: 1.写一个类MessageInfo对象,添加构造方法 虽然有快捷键,但是还是不够偷懒 项目添加Lombok。 Lombok是⼀个Java⼯具库,通过添加注…

Java | Leetcode Java题解之第283题移动零

题目&#xff1a; 题解&#xff1a; class Solution {public void moveZeroes(int[] nums) {int n nums.length, left 0, right 0;while (right < n) {if (nums[right] ! 0) {swap(nums, left, right);left;}right;}}public void swap(int[] nums, int left, int right)…