花了几天学习了网络爬虫这项技术,想要来试试手,于是就写了这第一个实实例。
然后我把目标看向了看的比较多的插画网站pixiv,稍微尝试了一下,其中也碰到了不少困难,还是要多看书,多学点东西。
主要的思路
1. 首先找到我们爬取的目标
也就是获取每日/每周/每月的热门作品排行,主要是插画(其他分区改一下就好)
网址:每日热门的网址
https://www.pixiv.net/ranking.php?mode=daily&content=illust&date=20200128
其中 ‘mode’ 有daily/weekly/monthly三个,风别对应每日,每周,和每月
其中 ‘content=illust’ 就是把分区设为插画
其中 ‘date’ 就是当前日期,可以任意改,但是形如20200101的年月日
2.通过上面这个网址的源代码获得每一幅插画的相关信息
就是从这一堆东西里面提取图片相关信息。(其实有json的文件,但是在我写这部分代码的时候我还没学,所以直接用正则表达式提取出来了)
3. 通过提取的信息保存
我提取出的信息有 排名,作品名,作者名,作品ID
通过提取出来的信息保存为TXT为后面所用
4.下载图片
因为提取出了作品id,那么就可以通过id去做页面访问
如今天的第一作品:https://www.pixiv.net/artworks/79117074
通过改变最后的ID访问到所有其他的插画
同样可以通过查找源代码等方式获得对应图片下载的url
5.最后以二进制保存图片
就用f.write(res.content)就好了
正式开始写
1.初始化
因为这个网站一定要登录才可以访问,所以就找到对应的cookies复制过来就好
然后为了反爬就改下header
# 从浏览器中找到对应的cookies复制到这里
self.cookie = ' *** '
# 初始化header,注意referer
self.header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36',
'Connection': 'keep-alive',
'accept': 'application/json, text/javascript, */*; q=0.01',
'Cookie': self.cookie,
'referer': '' # 随着对应需要访问的网址改变
}
2.获取相关信息
def get_image_url(self):
# 初始访问地址(通过系统的时间来获取今天的排行)
daily_url = 'https://www.pixiv.net/ranking.php?mode={}&content=illust&date={}'.format(self.times, self.date)
# 改变header
header = self.header.copy()
header['referer'] = daily_url
try:
# 获取网页源代码
html = requests.get(daily_url, headers=header).text
# 定义正则规则
regex = r'section id="(.*?)" class="ranking-item" data-rank="(.*?)" data-rank-text="(.*?)" data-title="(.*?)" data-user-name="(.*?)" data-date="(.*?)" data-view-count="(.*?)" data-rating-count="(.*?)" data-attr="(.*?)" data-id="(.*?)"'
# 通过正则规则和源代码获取图片信息
images_data = re.findall(regex, html)
# 翻页则通过改变p的值,然后从中提取相关信息(p=2,3,4,5...)
# https://www.pixiv.net/ranking.php?mode=daily&date=20200125&p=2&format=json
except:
print('无法获取图片相关信息')
return False
# 仅获取作品的 排名,作品名,作者名,作品ID
else:
image_data = []
for img in images_data:
image = {
'排名': img[0],
'作品名': img[3],
'作者名': img[4],
'作品id': img[9]
}
image_data.append(image)
if self.count == int(img[0]):
break
return image_data
3.获取对应下载的地址
其中的重点是 img_url的访问
通过访问img_url,在解析之后就访问判断图片是否有多P,并得到下载地址的列表
def save_img(self, image_date):
img_id = image_date['作品id']
# 因为图片可能多P,所以使用列表储存
down_list = []
# 改变header
header = self.header.copy()
header["Referer"] = "https://www.pixiv.net/member_illust.php?mode=medium&illust_id={}".format(img_id)
img_url = "https://www.pixiv.net/touch/ajax/illust/details?illust_id={}".format(img_id)
try:
data = requests.get(img_url, header, timeout=15)
except:
print("获取{}资源失败".format(img_id))
return False
else:
soup = bs4.BeautifulSoup(data.text, "html.parser")
try:
# 划重点(下面这段)
pre = json.loads(str(soup))["body"]["illust_details"]["manga_a"] # 列表
for i in range(len(pre)):
down_list.append(pre[i]["url_big"])
except KeyError:
pre = json.loads(str(soup))["body"]["illust_details"]["url_big"] # 字符串
down_list.append(pre)
# 将获得分图片下载地址、对用的header(改变referer)以及对用的排名return
img = down_list, header, image_date['排名']
return img
4.下载图片
# 以二进制保存图片(传入地址和图片相关信息)
def download_the_images(self, img):
try:
# 延时
time.sleep(2)
for im in range(len(img[0])):
file_name = img[2] + '_' + img[0][im].split("/")[-1]
img_url = img[0][im]
if not os.path.exists(self.img_path):
os.mkdir(self.img_path)
if not os.path.exists(self.img_path + file_name):
res = requests.get(img_url, headers=img[1])
res.raise_for_status()
with open(self.img_path + file_name, 'wb') as f:
f.write(res.content)
print('{}下载成功'.format(file_name))
except:
print('{}下载失败!!!'.format(file_name))
特别感谢
感谢 スイセーヨコ 大佬的代码 【传送门】
https://blog.csdn.net/water_blue_story/article/details/98974477
最后加个源代码
# coding: utf-8
import json
import bs4
import requests
import re
import os
import time
from urllib.request import urlretrieve
class download_image:
def __init__(self):
# 获取今日排名的日期
self.date = time.strftime('%Y%m%d', time.localtime(time.time() - 60 * 60 * 24))
# 保存图片数量
self.count = 9
self.times = 'daily'
self.img_path = ' *自己换个地址* ' + self.times + '_' + str(self.date) + '/'
# 从浏览器中找到对应的cookies复制到这里
self.cookie = ' *** '
# 初始化header,注意referer
self.header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36',
'Connection': 'keep-alive',
'accept': 'application/json, text/javascript, */*; q=0.01',
'Cookie': self.cookie,
'referer': '' # 随着对应需要访问的网址改变
}
def change_deploy(self):
y_n = input("是否改变日选周选月选(默认周选):(y/n)")
if y_n == 'y':
self.times = input("想按什么选?:(daily/weekly/monthly)")
y_n = input("是否改变日期(默认今天):(y/n)")
if y_n == 'y':
self.date = input("输入指定日期:")
y_n = input("是否改变获取张数(默认9,最多50):(y/n)")
if y_n == 'y':
self.count = input("输入需要获取的张数:")
y_n = input("是否改变文件储存地址:(y/n)")
self.img_path = 'I:/5.有趣的东西/image/' + self.times + '_' + str(self.date) + '/'
if y_n == 'y':
self.img_path = input("输入指定路径:")
print(self.img_path)
# 通过日期获得当日排名图片的相关信息
def get_image_url(self):
# 初始访问地址(通过系统的时间来获取今天的排行)
daily_url = 'https://www.pixiv.net/ranking.php?mode={}&content=illust&date={}'.format(self.times, self.date)
# 改变header
header = self.header.copy()
header['referer'] = daily_url
try:
# 获取网页源代码
html = requests.get(daily_url, headers=header).text
# 定义正则规则
regex = r'section id="(.*?)" class="ranking-item" data-rank="(.*?)" data-rank-text="(.*?)" data-title="(.*?)" data-user-name="(.*?)" data-date="(.*?)" data-view-count="(.*?)" data-rating-count="(.*?)" data-attr="(.*?)" data-id="(.*?)"'
# 通过正则规则和源代码获取图片信息
images_data = re.findall(regex, html)
# 翻页则通过改变p的值,然后从中提取相关信息(p=2,3,4,5...)
# https://www.pixiv.net/ranking.php?mode=daily&date=20200125&p=2&format=json
except:
print('无法获取图片相关信息')
return False
# 仅获取作品的 排名,作品名,作者名,作品ID
else:
image_data = []
for img in images_data:
image = {
'排名': img[0],
'作品名': img[3],
'作者名': img[4],
'作品id': img[9]
}
image_data.append(image)
if self.count == int(img[0]):
break
return image_data
def save_img(self, image_date):
img_id = image_date['作品id']
# 因为图片可能多P,所以使用列表储存
down_list = []
# 改变header
header = self.header.copy()
header["Referer"] = "https://www.pixiv.net/member_illust.php?mode=medium&illust_id={}".format(img_id)
img_url = "https://www.pixiv.net/touch/ajax/illust/details?illust_id={}".format(img_id)
try:
data = requests.get(img_url, header, timeout=15)
except:
print("获取{}资源失败".format(img_id))
return False
else:
soup = bs4.BeautifulSoup(data.text, "html.parser")
try:
pre = json.loads(str(soup))["body"]["illust_details"]["manga_a"] # 列表
for i in range(len(pre)):
down_list.append(pre[i]["url_big"])
except KeyError:
pre = json.loads(str(soup))["body"]["illust_details"]["url_big"] # 字符串
down_list.append(pre)
# 将获得分图片下载地址、对用的header(改变referer)以及对用的排名return
img = down_list, header, image_date['排名']
return img
# 以二进制保存图片(传入地址和图片相关信息)
def download_the_images(self, img):
try:
# 延时
time.sleep(2)
for im in range(len(img[0])):
file_name = img[2] + '_' + img[0][im].split("/")[-1]
img_url = img[0][im]
if not os.path.exists(self.img_path):
os.mkdir(self.img_path)
if not os.path.exists(self.img_path + file_name):
res = requests.get(img_url, headers=img[1])
res.raise_for_status()
with open(self.img_path + file_name, 'wb') as f:
f.write(res.content)
print('{}下载成功'.format(file_name))
except:
print('{}下载失败!!!'.format(file_name))
# 保存本次下载图片的相关信息
def download_images_information(self, image_data):
path = self.img_path
try:
file_name = path.split("/")[-2] + '.txt'
if not os.path.exists(self.img_path):
os.mkdir(self.img_path)
for imag in image_data:
with open(self.img_path + file_name, 'a+', encoding='utf-8') as f:
line = '排名:{}\n作品名:{}\n作者名:{}\n作品ID:{}\n\n'.format(imag['排名'], imag['作者名'], imag['作品名'], imag['作品id'])
f.writelines(line)
except:
print('文件保存失败!!!')
def main(self):
self.change_deploy()
# 获得图片信息(排名,作品名,作者名,作品ID)
image_data = self.get_image_url()
self.download_images_information(image_data)
for the_image in range(len(image_data)):
img = self.save_img(image_data[the_image])
self.download_the_images(img)
if __name__ == '__main__':
p = download_image()
p.main()
来源:CSDN
作者:Alivorth
链接:https://blog.csdn.net/Alivorth/article/details/104106639