360图片爬虫|批量爬取图片
360图片爬虫逆向,批量爬取360图片所有分类下的图片,结尾附完整代码
一、抓包分析
1.1思路分析
GET请求 https://image.so.com/c?ch=art&t1=1780
通过分析可以知道360图片的链接有两个参数ch和t1
ch参数表示为下方图片红色一栏的一级分类,如图所示的art表示艺术分类
t1参数表示为下方图片蓝色一栏的二级分类,如图所示的1780表示艺术名家欣赏
当我们查看抓包到的
https://image.so.com/z?a=filter&ch=art
的数据时 ,可以发现响应中有其对应的所有二级分类的中文名以及cat_id
cat_id就是开头的t1
因为一级分类较少,所以可以直接使用字典固定即可
categories = {
'art': '艺术',
'wallpaper': '壁纸',
'design': '设计',
'car': '汽车',
'food': '食物',
'home': '家具',
'pet': '宠物'
}
所以通过循环请求
https://image.so.com/z?a=filter&ch=art
就可以得到所有的二级分类对应的id和中文名
1.2爬取图片
GET请求 https://image.so.com/zjl?sn=0&ch=art&t1=200
sn——图片批次每次30张,0是这个分类下的1-30张图片,sn每次加30 比如sn=0.接下来就是sn=30
ch——一级分类字典
t1——二级分类id
可以看到sn=0时,该分类下的30张图像的信息
title——图像标题
qhimg_url——图像下载链接
通过分类获取好t1对应的id之后,再通过循环GET请求https://image.so.com/zjl?sn=0&ch=art&t1=200 获取标题和图像即可实现批量爬取360图片
二、代码实现
代码概要
tool.py —— 负责爬取各二级分类的id以及分类名称,效果如下
image.py —— 根据tool.py得到的id批量下载图片 ,效果如下
2.1分类id获取代码 tool.py
import os
import requests
import json
import csv
def fetch_and_save_categories(url, params, headers, output_file):
# 发送GET请求
response = requests.get(url, headers=headers, params=params)
# 检查响应状态码
if response.status_code == 200:
# 解析JSON响应
data = response.json()
# 检查是否存在 'result' 键
if 'result' in data and 'category' in data['result']:
categories = data['result']['category']
# 提取并写入CSV文件
def extract_categories(categories):
result = []
result.append({'cat_id': categories['cat_id'], 'cat_name': categories['cat_name']})
if '_child' in categories:
for child in categories['_child']:
result.extend(extract_categories(child))
return result
extracted_data = extract_categories(categories)
# 写入CSV文件
with open(output_file, 'w', newline='', encoding='utf-8') as file:
csv_writer = csv.writer(file)
csv_writer.writerow(['cat_id', 'cat_name'])
for item in extracted_data:
csv_writer.writerow([item['cat_id'], item['cat_name']])
print(f"数据已保存到 {output_file} 文件中")
else:
print("响应中没有找到预期的 'category' 键")
else:
print(f"请求失败,状态码: {response.status_code}")
# 请求的不同ch参数值
categories = {
'art': '艺术',
'wallpaper': '壁纸',
'design': '设计',
'car': '汽车',
'food': '食物',
'home': '家具',
'pet': '宠物'
}
url = 'https://image.so.com/z'
headers = {
'Host': 'image.so.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Accept-Encoding': 'gzip, deflate, br, zstd',
'Connection': 'keep-alive',
'Referer': 'https://image.so.com/c?ch=art',
'Cookie': 'QiHooGUID=2C41DF4F85C67A33C6AE6159D21836EE.1718195055756; __guid=16527278.2902233284592428000.1718195056738.8062; opqopq=8141981f1c97476ba46d47ebcc40c064.1718425129; _S=5975bd6fe122a862f99b36b09c3bf2dd',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'TE': 'trailers'
}
# 确保数据目录存在
data_dir = './data/title'
if not os.path.exists(data_dir):
os.makedirs(data_dir)
# 循环不同的ch参数值
for ch, category_name in categories.items():
params = {
'a': 'filter',
'ch': ch
}
output_file = os.path.join(data_dir, f"{ch}_categories.csv")
fetch_and_save_categories(url, params, headers, output_file)
2.2图像下载代码 image.py
import os
import requests
import re
import csv
import time
import random
import urllib3
# 禁用不安全请求警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def fetch_and_save_images(url, params, headers, save_folder):
print('****************'+url+'************')
print('****************' + str(params) + '************')
# 创建保存文件夹
if not os.path.exists(save_folder):
os.makedirs(save_folder)
# 发送GET请求,忽略SSL验证
try:
response = requests.get(url, headers=headers, params=params, verify=False)
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
return
# 检查响应状态码
if response.status_code == 200:
# 解析JSON响应
data = response.json()
print(str(data))
# 检查是否存在 'list' 键
if 'list' in data:
# 获取所有 'imgurl' 和 'title'
for item in data['list']:
img_url = item['qhimg_url']
title = item['title']
# 清理标题以便用作文件名
clean_title = re.sub(r'[\\/*?:"<>|]', "_", title)
# 下载图片
try:
img_response = requests.get(img_url, stream=True)
if img_response.status_code == 200 and 'image' in img_response.headers['Content-Type']:
file_path = os.path.join(save_folder, f'{clean_title}.jpg')
with open(file_path, 'wb') as handler:
for chunk in img_response.iter_content(1024):
handler.write(chunk)
print(f"图片已保存到: {file_path}")
# 设置下载间隔时间
else:
print(f"下载图片失败: {img_response.status_code}, 图片URL: {img_url}, 内容类型: {img_response.headers['Content-Type']}")
except requests.exceptions.RequestException as e:
print(f"下载图片失败: {e}, 图片URL: {img_url}")
else:
print(f"请求失败,状态码: {response.status_code}")
def get_categories_from_csv(csv_file):
categories = []
with open(csv_file, 'r', encoding='utf-8') as file:
csv_reader = csv.reader(file)
next(csv_reader) # 跳过标题行
for row in csv_reader:
categories.append({'cat_id': row[0], 'cat_name': row[1]})
return categories
# 请求的不同ch参数值
categories_dict = {
'art': '艺术',
'wallpaper': '壁纸',
'design': '设计',
'car': '汽车',
'food': '食物',
'home': '家具',
'pet': '宠物'
}
# 确保数据目录存在
data_dir = './data'
if not os.path.exists(data_dir):
os.makedirs(data_dir)
# 循环不同的ch参数值
for ch, category_name in categories_dict.items():
csv_file = f'./data/title/{ch}_categories.csv'
headers = {
'Host': 'image.so.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Accept-Encoding': 'gzip, deflate, br, zstd',
'Connection': 'keep-alive',
'Referer': f'https://image.so.com/c?ch={ch}',
'Cookie': 'QiHooGUID=2C41DF4F85C67A33C6AE6159D21836EE.1718195055756; __guid=16527278.2902233284592428000.1718195056738.8062; opqopq=8141981f1c97476ba46d47ebcc40c064.1718425129; _S=5975bd6fe122a862f99b36b09c3bf2dd',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'TE': 'trailers'
}
# 获取所有类别信息从CSV文件
categories = get_categories_from_csv(csv_file)
# 创建保存图片的基础目录
base_image_dir = os.path.join(data_dir, 'images',ch)
if not os.path.exists(base_image_dir):
os.makedirs(base_image_dir)
# 遍历所有类别并下载图片
for category in categories:
cat_id = category['cat_id']
cat_name = category['cat_name']
params = {
'sn': '0',
'ch': ch,
't1': cat_id
}
save_folder = os.path.join(base_image_dir, cat_name)
fetch_and_save_images('https://image.so.com/zjl', params, headers, save_folder)