Python を使用してグロー スキンの写真をクロールする (爬虫類に関する最も基本的な質問、Python クローラー チュートリアル、非常に詳細で完全なコード)

序文

現在、Python 言語を使用して栄光のすべてのヒーローのスキン写真を実現し、ダウンロードしてローカルに保存しています。完全なコードは記事の最後にあります。

1.思考分析

ウェブサイト分析

公式ウェブサイトにはたくさんのヒーローが表示され、各ヒーローはウェブページに対応しており、各ウェブページの URL の違いは番号であり (見に行くことができます)、登りたいスキンの写真がその中にあります。当時、ヒーローサイトのURL構築に何かルールがあるのではないかと推測しましたが、分析した結果、ルールが存在しないことが判明したため、公式サイトから各ヒーローサイトをクロールするしかありませんでした。ウェブサイトにアクセスし、それぞれをリクエストし(一部はクロールできず、非同期で読み込まれると推定されます)、スキンの写真を取得します。
ここに画像の説明を挿入
ここに画像の説明を挿入
ヒーロー Web サイトをリクエストすると、クロールされたデータは Web ページ内のデータとは異なります。
ここに画像の説明を挿入
ここに画像の説明を挿入
そこでパッケージをキャプチャしてスキン イメージのアドレスを見つけました。分析の結果、518 (各ヒーロー ページには特定の番号があります) が特定のロゴを表し、1 が最初のスキン イメージを表し、2 が最初のスキン イメージを表すことがわかりました。 , および 3 最初のスキンの写真を表し、以下同様です (他のものはこのようなものです)ここに画像の説明を挿入
その後、スキンの写真のアドレスを構築し、写真を取得するリクエストを送信するだけで済みますが、問題は再び発生します。番号をどうやって知るかということです。スキンの?? ヒーローのスキンは多い時もあれば少ない時もあり均一ではありませんが、実際にはヒーロー名1:写真1、ヒーロー名2:写真というように順番にスキン名とスキンの写真が対応していることが分かります。 2 ヒーロー名 3: 写真 3 というように、ヒーロー名から写真の数がわかり、各写真に対応する名前が得られるので一石二鳥です。コードのアイデアについて話しましょう
ここに画像の説明を挿入

コードのアイデア

公式サイトの各ヒーローに対応するURLをクロールし、スキン画像の数を1つずつリクエストして取得します(スキン画像の数がわからないと、スキン画像のアドレスを何個構築すればよいかわかりません) 、スキンの写真のアドレスを構築した後、1 つずつスキンのアドレスを要求し、スキンの写真を取得し、写真を 1 つずつ保存します。それは今のところすべてです。

2. 環境構築

# python+3.8.8
# requests  2.25.1
# parsel   1.6.0

# 安装
# pip install requests==2.25.1
# pip install parsel==1.6.0

# 如果觉得安装太慢,可以用镜像源
# pip install -i https://mirrors.tuna.tsinghua.edu.cn/help/pypi/ requests==2.25.1
# pip install -i https://mirrors.tuna.tsinghua.edu.cn/help/pypi/ parsel==1.6.0

3. 完全なコード

import requests
import parsel
import os  # 内置库不需要安装
import re  # 内置库不需要安装
import logging  # 内置库不需要安装


# 发送请求
def get_url(url):
    headers = {
    
    
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'accept-language': 'zh-CN,zh;q=0.9',
        'pragma': 'no-cache',
        'referer': 'https://pvp.qq.com/',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36'}

    response = requests.get(url=url, headers=headers)
    # 获取网页编码,避免乱码
    response.encoding = response.apparent_encoding
    return response


# 解析数据
def parser_data(html_data, css_rule, css_1, css_2):
    # 传入html数据
    html = parsel.Selector(html_data)

    # 二次提取
    li = html.css(css_rule)

    data_list = []
    for i in li:
        # 获取英雄名(皮肤名)
        name = i.css(css_1).get()
        # 获取网页地址(图片地址)
        url_data = i.css(css_2).get()
        data_list.append([name, url_data])
    # [[],[],[]......]
    return data_list


def first_data(url):
    html_1 = get_url(url).text
    data_list = parser_data(html_1, '.herolist li', 'a::text', 'a::attr(href)')
    u = []
    for k in data_list:
        # 提取网址中的数字,后面构造图片地址用
        num = re.findall(r'\d+', k[1])[0]
        # 构造每一个英雄的网页地址
        url_ju = 'https://pvp.qq.com/web201605/' + k[1]
        # 替换原先的地址
        k[1] = url_ju
        k.append(num)
        u.append(k)
        print(k)
    # 返回形式[[],[],[],[].....]
    return u


def second_data(url_list):
    total = []

    for g in url_list:
        html_2 = get_url(g[1]).text
        # 皮肤名字爬取不到了,返回为None
        data = parser_data(html_2, '.pic-pf-list ', 'li p::text', '::attr(data-imgname)')
        # 将None值删除
        for y in data:
            y.remove(None)
        # 将英雄名和数字插入
        data[0].insert(0, g[0])
        data[0].insert(1, g[2])
        total.append(data)
        print(data)
    # [[],[],[],[]......]
    return total


def save_file(data, dir_name, file_name):
    '''

    :param data: 图片数据
    :param dir_name: 英雄的目录名
    :param file_name: 保存图片的文件名
    :return:
    '''
    if not os.path.exists('荣耀图片'):
        os.mkdir('荣耀图片')

    if not os.path.exists('王者图片\\' + dir_name):
        os.mkdir('荣耀图片\\' + dir_name)

    with open('荣耀图片\\' + dir_name + '\\' + file_name + '.jpg', mode='wb') as f:
        f.write(data)


# 去除特殊字符,返回集合
def del_str(data_str):
    name_list = []
    jpg_name = data_str.split('|')
    for h in jpg_name:
        t = h.replace('&', '')
        for number in range(10):
            t = t.replace(str(number), '')
        name_list.append(t)
    return name_list, len(name_list)


if __name__ == '__main__':
    # 设置输出的格式
    LOG_FORMAT = "时间:%(asctime)s - 日志等级:%(levelname)s - 日志信息:%(message)s"
    # 对logger进行配置——日志等级&输出格式
    logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)
	
	# 官网地址!!!
    url = ''
    d = first_data(url)

    total_list = second_data(d)
    logging.info('总共' + str(len(total_list)) + '个英雄')
    logging.info('开始爬取图片')
    a = 1
    # 遍历每一条数据
    for n in total_list:
        # 计数 英雄数
        dir_name = str(a) + '.' + n[0][0]
        logging.info('正在爬取' + dir_name + '皮肤')
        # 特定的英雄id
        num_id = n[0][1]
        # 传入皮肤名 返回一个集合 ([皮肤名],皮肤数)
        name_num = del_str(n[0][-1])
        a += 1
        # 构建图片地址,并爬取,皮肤地址是从1开始
        for j in range(1, name_num[1] + 1):
            logging.info('正在爬取' + name_num[0][j - 1])
            jpg_url = f'https://game.gtimg.cn/images/yxzj/img201606/skin/hero-info/{
      
      num_id}/{
      
      num_id}-bigskin-{
      
      j}.jpg'
            # 爬取皮肤图片
            jpg_content = get_url(jpg_url).content
            # 保存图片
            save_file(jpg_content, dir_name, name_num[0][j - 1])
            logging.info('已保存' + name_num[0][j - 1])
    logging.info(str(len(total_list)) + '个英雄' + '爬取完毕!')



4. まとめ

クロールのスキン画像は比較的基本的なもので、初心者がクロールを練習するのに適しています。肌絵を登りすぎると逆転されて、這えないものもあるのですが、最初は登れるのですが、何度も這うと登れなくなると記憶しています。 IPを変更して遅延時間を設定してみるか、Seleniumを使用してクロールしてください。
記事に間違いがある場合は修正してください。最後に感謝します。

おすすめ

転載: blog.csdn.net/qq_65898266/article/details/124870582