首页 > 其他分享 >用Xpath制作简单爬虫工具,获取神奇宝贝百科的精灵信息

用Xpath制作简单爬虫工具,获取神奇宝贝百科的精灵信息

时间:2024-06-17 22:00:29浏览次数:22  
标签:Xpath xpath 可梦 百科 tree 爬虫 text td class

最近开始学习Python的爬虫应用,个人比较喜欢用Xpath的方式来爬取数据,今天就结合一下Xpath方式,以“神奇宝贝百科”为素材,制作一个爬取每只宝可梦数据的工程项目

准备工作
神奇宝贝百科地址:https://wiki.52poke.com/wiki/主页
工程项目的目标是,获取每只精灵的名字、编号、属性、特性、以及蛋群,比如这个妙蛙花页面的例子

我们可以先看看这个网站逻辑是怎么样的,妙蛙花的图鉴地址是这个:https://wiki.52poke.com/wiki/妙蛙花
和主页相比,wiki后面跟着的内容实际上是精灵的文本编码,那么我们就需要得到每只精灵的文本编码是多少了,而在神奇宝贝百科中,在全国图鉴页面中,刚好就可以查看全部宝可梦的名字

全国图鉴页面地址:https://wiki.52poke.com/wiki/宝可梦列表(按全国图鉴编号)
在这个页面里面,点击每只精灵的名字,就可以跳转到对应精灵的图鉴页面中去,也就是说这个页面里面,应该会包含每只宝可梦图鉴页面的超链接,我们可以用开发者模式看看

用元素查找器点击妙蛙种子的名字,查找到了这只宝可梦的超链接,点击进去,果然就是跳转到了妙蛙种子的图鉴页面了,这边爬虫的基本逻辑就是,先获取每只宝可梦的超链接,再逐个超链接来解析宝可梦的数据,并爬取获得

开始编码

#urllib中的URL拼接库
from urllib.parse import urljoin

#导入request库
import requests

#导入re库
import re

#导入日志信息库
import logging

#导入文件写入库
import json
from os import makedirs
from os.path import exists

#导入lxml库
from lxml import etree

#日志输出级别和输出格式
logging.basicConfig(level=logging.INFO,format='%(asctime)s-%(levelname)s:%(message)s')

#打开文件夹results,如果没有,就创造一个这样的文件夹
RESULTS_DIR = 'results'
exists(RESULTS_DIR) or makedirs(RESULTS_DIR)

首先,导入一些基本的库,以方便我们使用对应的功能,由于最终的结果是导出JSON格式的文件,所以也导入了JSON的库
之后按照上一步的分析,把网址的根部URL,以及全国图鉴的URL以常量的方式作为一个常量编写到程序中,:

#当前站点的根目录
BASE_URL = 'https://wiki.52poke.com'
#测试用网站
GOAL_URL = 'https://wiki.52poke.com/wiki/%E5%AE%9D%E5%8F%AF%E6%A2%A6%E5%88%97%E8%A1%A8%EF%BC%88%E6%8C%89%E5%85%A8%E5%9B%BD%E5%9B%BE%E9%89%B4%E7%BC%96%E5%8F%B7%EF%BC%89'

第一步,先发送get请求,获取目标网页的代码,创建一个这样的函数来实现功能:

#抓取网页源代码函数
def scrape_page(url):
    #打印日志信息
    logging.info('scraping %s...',url)
    try:
        response = requests.get(url)
        if response.status_code == 200:
            #如果状态码是200,直接返回源代码,否则捕捉异常
            return response.text
        logging.error('get invalid status code %s while scraping %s',response.status_code,url)
    except requests.RequestException:
        logging.error('error occurred while scraping %s',url,exc_info=True)

第二步,创建每只宝可梦的地址列表,我们可以通过解析全国图鉴的url,并根据起初观察的地址结构,来获得每只宝可梦的超链接

#获取每只宝可梦的网页代码函数
def parse_index(html):
    #将网页源码解析为lxml树
    tree = etree.HTML(html)
    #用lxml树来获取目标a节点的href属性
    elements = tree.xpath('//td[@class = "rdexn-name"]/a/@href')
    #如果没有数据,返回空列表,否则返回处理后的地址列表
    if not elements:
        return []
    for element in elements:
        #把根目录和href属性的值结合成每只宝可梦的页面地址
        detail_url = urljoin(BASE_URL,element)
        logging.info('get detail url %s',detail_url)
        yield detail_url


根据网页的逻辑,精灵的超链接都放在了class属性为rdexn-name的td节点下的a节点的href属性里面,所以这里用Xpath的结构//td[@class = "rdexn-name"]/a/@href来获取里面的值,通过urllib库下的urljion方法,把BASE_URL和href属性值合起来,就能得到每只宝可梦的页面链接,之后再以生成器对象返回

#抓取每只宝可梦的详细页面代码函数
def scrape_detail(url):
    return scrape_page(url)

创建一个专门抓取每只宝可梦详细页面的函数,这里直接调用之前解析网页的函数就可以了,之后就是抓取最重要的数据部分了,也是最复杂的一步

重点分析
第一步最简单,先创建一个解析精灵数据的函数,依然使用Xpath的对象树的方法来创建解析对象

#解析每只宝可梦的内容,包括属性、编号、名字、特性、蛋群
def parse_details(html):

    #将网页源码解析为lxml树
    tree = etree.HTML(html)

接下来就是重点环节了,要获取精灵的属性,就要观察它的网页结构是怎么样的:

每只宝可梦基本上有1~2种属性,根据网页结构,属性的路径表达可以是这样子:

#属性
types = tree.xpath('//table[@class = "roundy bgwhite fulltable"]//td[contains(@class,"roundy")]/a//span[@class = "type-box-9-text"]/text()')


编号就更简单了,直接找到title属性为“宝可梦列表(按全国图鉴编号)”的a标签,获取文本属性就可以了

#编号
number = tree.xpath('//a[@title = "宝可梦列表(按全国图鉴编号)"]/text()')


名字也很简单,直接获取style等于font-size:1.5em的span标签下的b标签的文本属性就可以了

#名字
name = tree.xpath('//span[@style = "font-size:1.5em"]/b/text()')

特性的话会相对比较麻烦,每只精灵至少有1种基本特性,而至多有两种基本特性,但是隐藏特性也属于精灵的特性,而且并不是每只精灵都会有隐藏特性的,例如铁甲蛹这只精灵


所以网页的结构也因此而不同,可以观察到,有隐藏特性和没隐藏特性的路径,是不一样的,没有隐藏特性的精灵,td的标签没有colspan这个属性,如果用同一种写法,可能会引起获取不到特性的问题


因此这就需要加上逻辑判断,根据情况来决定路径的执行,思路是根据上面td属性的区别来作出判断,找到这边标签的Xpath路径之后,作为if语句的判断条件,特性的路径语句也不难,找到包含“特性”字符的title属性就可以了

#特性
#如果没有隐藏特性
hide_feature = tree.xpath('/table[contians(@class,"roundy")]/tbody/tr[4]/td[@colspan = "2"]')
if not hide_feature:
    features = tree.xpath('//td/table[@class = "roundy bgwhite fulltable"]/tbody//a[contains(@title,"(特性)")]/text()')
else:
    features = tree.xpath('//td[@colspan = "2"]//a[contains(@title,"(特性)")]/text()')
        


蛋群属性也不难,按照页面逻辑,找到colspan属性的td标签下,包含“蛋群”字眼的title属性的a标签,获取文本就可以了

#蛋群
eggs = tree.xpath('//td[@colspan = "2"]//a[contains(@title,"(蛋群)")]/text()')

最后再将获取到的数据,以字典的形式返回,这样一来,就能得到一只宝可梦的属性、编号、名字、特性、蛋群的信息

return{
    'types':types,
    'number':number,
    'name':name,
    'features':features,
    'eggs':eggs
    }

这样的代码看似没问题,不过宝可梦有个设定就是,有些宝可梦可能会有其他形态,比如妙蛙花这只精灵,有超级进化,以及超极巨化的形态,那么要获取它的信息的时候,可能会出现数据重复的问题,这种情况是因为具有多种形态的宝可梦,网页结构不一样的原因


可以看到,妙蛙花因为具有多个形态的原因,网页结构上多了几个class属性为_toggle from的属性,那么就需要多做一步判断处理,这里只取他最基本的形态的数据为主,代码如下:

#解析每只宝可梦的内容,包括属性、编号、名字、特性、蛋群
def parse_details(html):

    #将网页源码解析为lxml树
    tree = etree.HTML(html)

    #判断是否有额外形态
    toggle = tree.xpath('//tr[@class = "_toggle form1"]')
    
    #根据是否有额外形态,来进行解析筛选
    if toggle:
        #属性
        types = tree.xpath('//tr[@class = "_toggle form1"]//table[@class = "roundy bgwhite fulltable"]//td[contains(@class,"roundy")]/a//span[@class = "type-box-9-text"]/text()')
        #编号
        number = tree.xpath('//tr[@class = "_toggle form1"]//a[@title = "宝可梦列表(按全国图鉴编号)"]/text()')
        #名字
        name = tree.xpath('//tr[@class = "_toggle form1"]//span[@style = "font-size:1.5em"]/b/text()')
        
        #特性
        #如果没有隐藏特性
        hide_feature = tree.xpath('/table[contians(@class,"roundy")]/tbody/tr[4]/td[@colspan = "2"]')
        if not hide_feature:
            features = tree.xpath('//tbody/tr[contains(@class,"_toggle form1")]//td//a[contains(@title,"(特性)")]/text()')
        else:
            features = tree.xpath('//tbody/tr[contains(@class,"_toggle form1")]//td[@colspan = "2"]//a[contains(@title,"(特性)")]/text()')
            
        #蛋群
        eggs = tree.xpath('//tr[@class = "_toggle form1"]//td[@colspan = "2"]//a[contains(@title,"(蛋群)")]/text()')
    else:
        #属性
        types = tree.xpath('//table[@class = "roundy bgwhite fulltable"]//td[contains(@class,"roundy")]/a//span[@class = "type-box-9-text"]/text()')
        #编号
        number = tree.xpath('//a[@title = "宝可梦列表(按全国图鉴编号)"]/text()')
        #名字
        name = tree.xpath('//span[@style = "font-size:1.5em"]/b/text()')
        
        #特性
        #如果没有隐藏特性
        hide_feature = tree.xpath('/table[contians(@class,"roundy")]/tbody/tr[4]/td[@colspan = "2"]')
        if not hide_feature:
            features = tree.xpath('//td/table[@class = "roundy bgwhite fulltable"]/tbody//a[contains(@title,"(特性)")]/text()')
        else:
            features = tree.xpath('//td[@colspan = "2"]//a[contains(@title,"(特性)")]/text()')
        
        #蛋群
        eggs = tree.xpath('//td[@colspan = "2"]//a[contains(@title,"(蛋群)")]/text()')
      
    return{
        'types':types,
        'number':number,
        'name':name,
        'features':features,
        'eggs':eggs
        }

最后一步是把数据导出为JSON文件格式

#保存为JSON格式
def save_data(data):
    name = data.get('name')
    data_path = f'{RESULTS_DIR}/{name}.json'
    json.dump(data,open(data_path,'w',encoding='utf-8'),ensure_ascii=False,indent=2)

所有的功能性代码就已经全部完成了,最后只需要执行主函数,让程序运行起来,就可以自动抓取每只宝可梦的数据了

#主函数
def main():

    #获取全国图鉴的页面信息
    html = scrape_page(GOAL_URL)
    #获取每只精灵的超链接代码
    detail_urls = parse_index(html)
    
    #把每只宝可梦的详情页逐个分析,用data的变量来存取
    for detail_url in detail_urls:
        detail_html = scrape_detail(detail_url)
        data = parse_details(detail_html)
        logging.info('get detail data %s',data)
        logging.info('saving data to json file')
        save_data(data)
        logging.info('data saved successfully')
        
#运行程序
if __name__=='__main__':
    main()        

之后就可以获得每只宝可梦的JSON文件了,里面包括每只精灵的属性、编号、名字、特性、蛋群信息


标签:Xpath,xpath,可梦,百科,tree,爬虫,text,td,class
From: https://www.cnblogs.com/GodWolley/p/18253294

相关文章

  • 用Xpath制作简单的爬取网页工具,获取神奇宝贝百科每只精灵的信息
    最近开始学习Python的爬虫应用,个人比较喜欢用Xpath的方式来爬取数据,今天就结合一下Xpath方式,以“神奇宝贝百科”为素材,制作一个爬取每只宝可梦数据的工程项目准备工作神奇宝贝百科地址:https://wiki.52poke.com/wiki/主页工程项目的目标是,获取每只精灵的名字、编号、属性、特性......
  • 基于springboot的南门桥社区疫情防疫系统-48138(免费领源码+数据库)可做计算机毕业设计J
    Springboot南门桥社区疫情防疫系统的设计与实现摘 要信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对南门桥社区疫情防疫系统等问题,对南门桥社区......
  • 百度翻译逆向Acs-Token逆向百度翻译爬虫(调试篇)
    文章声明本文章中所有内容仅供学习交流,严禁用于商业用途和非法用途,否则由此产生的一切后果均与文章作者无关,若有侵权,请联系我立即删除!概要-该篇文章是基于translate接口的分析-用到的工具Edge浏览器逆向目标求参数Acs-Token上一篇百度翻译是技巧篇,这篇来带着......
  • Python爬虫下载漫画
    《谒金门·萧瑟霜》情眷恋古往今来相看几度流光人更远伤离方寸乱回梦空传幽怨依旧尘缘未断碧落黄泉寻觅遍愁来天不管最近有个轻小说改编动漫《在异世界迷宫开后宫》开播,看着还行,小说一般,流水账的感觉,而且目前国内暂时没有文库版的翻译,只有web版的个人翻译,不过对应......
  • Python爬虫获取B站漫画
    《眼儿媚·朦胧雾》身世飘零叹孤独回顾盼相扶情天不老雷霆易逝雨过云舒相思不忍轻离别携手更如初风急波涌扁舟不系终恋江湖最近有妖气上《鬼刀》停止更新了,Bilibili漫画上的又不能下载保存到本地,加上最近正在玩StyleGANs,需要一些动漫图片做训练数据集,所以搞个爬......
  • Web爬虫-edu_SRC-目标列表爬取
    免责声明:本文仅做技术交流与学习...爬取后,结合暗黑搜索引擎等等进行进一步搜索.edu_src.pyimportrequests,timefrombs4importBeautifulSoupforiinrange(1,20):url=f'https://src.sjtu.edu.cn/rank/firm/0/?page={i}'print(f"正在获取第{i}页......
  • Python爬虫之路(12)--re正则表达式
    正则表达式认识正则正则表达式,又称规则表达式,(RegularExpression,在代码中常简写为regex、regexp或RE),是一种文本模式,包括普通字符(例如,a到z之间的字母)和特殊字符(称为"元字符"),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个语法规则的......
  • Python爬虫入门与实践
    在当今的互联网时代,网络爬虫已经成为获取网络数据的重要工具。Python作为一种强大的编程语言,其简洁易读和丰富的库支持使得它成为爬虫开发的首选语言。本文将带你入门Python爬虫,并通过一个简单的示例来展示如何使用Python爬取网页数据。一、Python爬虫基础Python爬虫通常包括......
  • 写个简单的爬虫案例
    以下是一个简单的爬虫案例,用于从网页上爬取图片并保存到本地:```pythonimportrequestsfrombs4importBeautifulSoupimportos#创建一个文件夹用于保存图片ifnotos.path.exists('images'):  os.makedirs('images')#网页URLurl='https://www.example.com'#......
  • 爬虫 | 异步请求aiohttp模块
    aiohttp模块,也就是asynciohttp操作#1.创建一个对象aioreq=aiohttp.ClientSession()>>>即对应异步的requests#2.用这个异步requests来发送请求resp=aioreq.get(url)#3.异步写入文件,用到aiofiles模块,pip安装,可学习:https://www.w3cschool.cn/article/86236403.h......