使用python爬取P站图片

刚开学时有一段时间周末没事,于是经常在P站的特辑里收图,但是P站加载图片的速度比较感人,觉得自己身为计算机专业,怎么可以做一张张图慢慢下这么low的事,而且这样效率的确也太低了,于是就想写个程序来帮我下,但是只会C与c++的我看来是无法用他们来做这事的,于是就去学了下简单,强大的python,不得不说,python的模块的确叼,依靠几个模块就可以在完全不知道原理的前提下让程序执行相应功能,这样虽然爽但对于学习不利,我这次就权当写着玩吧,在我学会怎样使用c++来做这事之前我不会再使用python编程了,不过写这个程序过程中我还是知道了一些东西,比如坑爹的编码问题,还有http的一点知识,还有能大概读懂html了,不过,不是通过系统学习,并没有什么卵用。废话不多说,来看代码吧。

from bs4 import BeautifulSoup
import requests
from PIL import Image
from io import BytesIO
import os
import codecs
import sys
headers={
    ‘Accept‘:‘text/html‘,
    ‘Accept-Language‘:‘zh-CN,zh;q=0.8‘,
    ‘Referer‘:"",
    ‘User-Agent‘:"此处为浏览器的user-agent"#浏览器数据
}
order=1
def getpic (src,href,mode=""):
     os.system("cls")
     print("共有%d个文件需要下载"%number_of_file)
     if src[-3:] == "gif":
         return‘‘‘使用gif来保存静态图片的都是邪教‘‘‘
     headers[‘Referer‘] = href
     ispng=False
     url=src.replace("_master1200","")
     url=url.replace(url[20:40],"img-original")
     if mode==‘mul‘:
        print(‘正在下载第%d个...‘%order)
        print("该文件含有多张图:")
     else:
        print(‘正在下载第%d个...‘%order)
     if os.path.exists(file_path+(url.replace(‘/‘,""))[-15:]):
         print(‘已下载第%d个‘%order)
         return
     else:
         data=requests.get(url,headers=headers,timeout=60)
     if str(data)!=‘<Response [200]>‘:
        ispng=True
        url=url.replace("jpg","png")
     if mode == ‘mul‘:
         if ispng:
             print("********正在下载第1张")
             if os.path.exists(file_path+(url.replace(‘/‘,""))[-15:]):
                pass
             else:
                 data=requests.get(url,headers=headers)
                 im=Image.open(BytesIO(data.content))
                 im.save(file_path+(url.replace(‘/‘,""))[-15:],‘png‘)
             print("********已下载第1张")
             for i in range(150):
                 url=url.replace("p%d.png"%i,"p%d.png"%(i+1))
                 os.system("cls")
                 print("********正在下载第%d张..."%(i+2))
                 if os.path.exists(file_path+(url.replace(‘/‘,""))[-15:]):
                    pass
                 else:
                    data=requests.get(url,headers=headers,timeout=60)
                    if str(data)!=‘<Response [200]>‘:
                        break
                    im=Image.open(BytesIO(data.content))
                    im.save(file_path+(url.replace(‘/‘,""))[-15:],‘png‘)
                 print("********已下载第%d张"%(i+2))
         else:
             print("********正在下载第1张")
             if os.path.exists(file_path+(url.replace(‘/‘,""))[-15:]):
                pass
             else:
                 data=requests.get(url,headers=headers,timeout=60)
                 im=Image.open(BytesIO(data.content))
                 im.save(file_path+(url.replace(‘/‘,""))[-15:],‘jpeg‘)
             print("********已下载第1张")
             for i in range(150):
                 url=url.replace("p%d.jpg"%i,"p%d.jpg"%(i+1))
                 os.system("cls")
                 print("********正在下载第%d张..."%(i+2))
                 if os.path.exists(file_path+(url.replace(‘/‘,""))[-15:]):
                     pass
                 else:
                     data=requests.get(url,headers=headers,timeout=60)
                     if str(data)!=‘<Response [200]>‘:
                         break
                     im=Image.open(BytesIO(data.content))
                     im.save(file_path+(url.replace(‘/‘,""))[-15:],‘jpeg‘)
                 print("********已下载第%d张"%(i+2))
     else:
         if ispng :
            if os.path.exists(file_path+(url.replace(‘/‘,""))[-15:]):
                print(‘已下载第%d个‘%order)
                return
            else:
                data=requests.get(url,headers=headers,timeout=60)
                if str(data) == ‘<Response [200]>‘:
                 im=Image.open(BytesIO(data.content))
                 im.save(file_path+(url.replace(‘/‘,""))[-15:],‘png‘)
                print(‘已下载第%d个‘%order)
         else:
            im=Image.open(BytesIO(data.content))
            im.save(file_path+(url.replace(‘/‘,""))[-15:],‘jpeg‘)
            print(‘已下载第%d个‘%order)

number=sys.argv[1]
file_path=sys.argv[2]+‘\\Picture\\‘#修改此处即可改变路径
url_save="http://spotlight.pics/zh/a/%s"%number
wb=requests.get(url_save,headers=headers)
wb_data=BeautifulSoup(wb.text,‘lxml‘)
title=wb_data.h2.string.replace("\n","").replace(":","").replace("?","").replace("\"","").replace(" ","")
title=title.replace("<","").replace(">","").replace("|","").replace("*","").replace("/","").replace("\\","")
#依据windows目录命名规则
file_path=(file_path+title)+"\\"
‘‘‘判断文件是否存在‘‘‘
if not os.path.exists(file_path):
    introduce=str(wb_data.h2.next_sibling.next_sibling.next_element)
    os.mkdir(file_path)
    f=codecs.open(file_path+"介绍.txt","w","utf-8")
    f.write("特辑号:%s\n"%number+introduce)
    f.close()
divs=wb_data.body.select(‘div[class="illust-wrap"]‘)
number_of_file=len(divs)
headers[‘Accept‘]=‘image/webp,image/*,*/*;q=0.8‘
for div in divs:
  if str(div.a.parent[‘class‘])!=‘[\‘ugoira-player\‘, \‘ui-scroll-view\‘]‘:
    if str(div.a.parent[‘class‘])==‘[\‘illust-multi-page-wrap\‘]‘:
        getpic(div.img[‘src‘],div.a[‘href‘],"mul")
    else:
        getpic(div.img[‘src‘],div.a[‘href‘])
    #要想好动图怎么办
  order+=1

说一下,写程序过程中遇到的问题。

先说主要思路,我们来看一下P站的特辑页面

<div class="illust-wrap">
<a href="http://www.pixiv.net/member_illust.php?mode=medium&amp;illust_id=56543092" class="inner-link" onclick="ga(‘send‘, ‘event‘, ‘Article‘, ‘ClickIllustImage‘, 56543092);">
<img src="http://i1.pixiv.net/c/480x960/img-master/img/2016/04/26/15/59/36/56543092_p0_master1200.jpg">
</a>
</div>

这是一个图片url的语句块,可以看到图片的url与图片对应的页面链接,但这个url不是高清图的,高清图的url要在链接对应页面里找,正常来说,我们应该request一下那个链接,请求一下html,再对那个页面中的数据提供的大图url进行request,这才是正规途径,但是,我通过观察大图url发现,只要将小图url的一些地方进行替换就是大图的url,于是我就干脆,试探性地request,只要返回的不是

404,那么说明就是大图的url,那么我们就可以把request返回的数据通过byteio写成图片,就相当于下载了。基本思路就是,寻找预览图对应url---》修改预览图url---》request获得数据---》保存数据为图片。所以,主要的问题就是如何分析网页获取图片url,此外,有一点要说的就是,对于含多张图的url,我采用request到返回404为止的方式,又是一招粗暴的方法,正确方法还是获取网页数据并分析确定图片数目,但是,我一开始不知道可以控制request得到数据的类型,于是觉得少request一下更划算,现在看来真是自作聪明,不过这样对性能的影响是好是坏我不清楚,这主要取决于request不存在的url返回404的速度,后来也懒得改了,因为我发现,速度本来就不乐观,网速好的时候还好,网速差的时候真的是。。。。

然后说一下,写程序过程中遇到的各种bug

问题 1:按特辑保存文件,文件名有可能有unicode字符,而默认的文本保存是gbk,这样就会编码错误。

解决方法:使用codecs已utf-8的编码来写文件。

问题 2:动图的处理。

解决方法:我可以假装看不见(去死吧!),好吧,讲真的,总的来说,特辑里的动图相对而言数量少,我觉得不下没关系,但是如果要下的话,P站那里也没有提供高清图的url,我可以加点代码让他下,但是下不了高清,个人觉得不是高清图的话要他何用?

问题 3:gif图,p站图片大部分格式都是png与jpg这两种主流格式,极少部分是gif,我也是在大量测试(收图)的情况下才发现居然有这种坑。

解决方法:我可以再假装看不见,好吧,讲真的。是因为gif真的很少,我为了解决这个bug就得多加一个判断,这样我觉得得不偿失,(这主要是我不访问链接页面获取url数据留下的锅),于是就拒绝下gif,另一个就是无论如何我都很难接受不是动图却使用gif的事实。。。

问题 4: header 的制定。

解决方法:一开始不知道,怎样也request不到图片,傻傻地加了cookie也没用,后来才发现只要user—agent与referer就好了,另外,默认的文字是英文,要加上language才能得到中文标题。

问题 5:windows目录名问题

解决方法:将所有标题中的非法字符去掉,这个真的没办法,这是微软的锅,就算会让标题看起来显得奇怪我也只能去掉。

以上就是所有编程过程中的问题了,最后解释一下这段代码,写这段代码的过程我是使用python3.5来作为解释器,这段代码的功能是接受两个参数,特辑号与保存路径。他就会在路径下创建一个目录名为特辑标题的文件夹,然后将专辑中的所有非动图与gif下载到文件夹中,因为我没有队列开多线程优化(我也不会的说),所有速度比较感人。还有值得一提的是,路径中必须有名为Picture的文件夹,所有特辑都会保存在其中,我觉得这种事不用交给程序,于是就没写进去。

其实这段代码能有效运行,主要功劳都属于beautifulsoup与request这两个功能强大,封装性好的模块(也许太好了,以至于我根本不清楚它的原理,有点小郁闷)。

此外,有了以上那个getpic函数,我们通过分析页面,就可以下载P站各个模块的图。P站具有标签功能与图片的热度显示,对标签较好的维护,使得海量图片有效的组织,图片的热度可以看作图片质量的衡量指标,这也许能看作P站的一个卖点,至少,它自己的确是把这看作是一个卖点,收费20RMP一个月就可以支持按热度搜索标签内容,但我穷,只能写程序来偷偷拥有这个功能,其实,有了getpic,这就不是难事了,但问题是,只有注册用户在登陆后才看到到热度,也就是,要在header中加上注册用户的cookie,一开始不知道,还以为是各种动态脚本生成的加密算法之类的,结果我还是高估了P站程序员的良心。嗯,顺便也贴写代码吧。

from bs4 import BeautifulSoup
from PIL import  Image
import  os
import requests
from io import BytesIO
import sys
headers={
    ‘Accept‘:‘‘,
    ‘Accept-Language‘:‘zh-CN,zh;q=0.8‘,
    ‘Referer‘:"",
    ‘User-Agent‘:"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",#浏览器数据
    ‘Cookie‘:""
}
cookies=""
def getpic (src,href,mode=""):
     if src[-3:] == "gif":
         return‘‘‘使用gif来保存静态图片的都是邪教‘‘‘
     headers[‘Referer‘] = href
     ispng=False
     url=src.replace("_master1200","")
     url=url.replace(url[20:40],"img-original")
     if mode==‘mul‘:
        print("该文件含有多张图:")
     else:
        print(‘正在下载...‘)
     if os.path.exists(file_path+(url.replace(‘/‘,""))[-15:]):
         print(‘下载完成‘)
         return
     else:
         data=requests.get(url,headers=headers,timeout=60)
     if str(data)!=‘<Response [200]>‘:
        ispng=True
        url=url.replace("jpg","png")
     if mode == ‘mul‘:
         if ispng:
             print("********正在下载第1张")
             if os.path.exists(file_path+(url.replace(‘/‘,""))[-15:]):
                pass
             else:
                 data=requests.get(url,headers=headers,timeout=60)
                 if str(data) == ‘<Response [200]>‘:
                  im=Image.open(BytesIO(data.content))
                  im.save(file_path+(url.replace(‘/‘,""))[-15:],‘png‘)
             print("********已下载第1张")
             for i in range(150):
                 url=url.replace("p%d.png"%i,"p%d.png"%(i+1))
                 os.system("cls")
                 print(‘正在下载第%d页...‘%page)
                 print("********正在下载第%d张..."%(i+2))
                 if os.path.exists(file_path+(url.replace(‘/‘,""))[-15:]):
                    pass
                 else:
                    data=requests.get(url,headers=headers,timeout=60)
                    if str(data)!=‘<Response [200]>‘:
                        break
                    im=Image.open(BytesIO(data.content))
                    im.save(file_path+(url.replace(‘/‘,""))[-15:],‘png‘)
                 print("********已下载第%d张"%(i+2))
         else:
             print("********正在下载第1张")
             if os.path.exists(file_path+(url.replace(‘/‘,""))[-15:]):
                pass
             else:
                 data=requests.get(url,headers=headers,timeout=60)
                 im=Image.open(BytesIO(data.content))
                 im.save(file_path+(url.replace(‘/‘,""))[-15:],‘jpeg‘)
             print("********已下载第1张")
             for i in range(150):
                 url=url.replace("p%d.jpg"%i,"p%d.jpg"%(i+1))
                 os.system("cls")
                 print(‘正在下载第%d页...‘%page)
                 print("********正在下载第%d张..."%(i+2))
                 if os.path.exists(file_path+(url.replace(‘/‘,""))[-15:]):
                     pass
                 else:
                     data=requests.get(url,headers=headers,timeout=60)
                     if str(data)!=‘<Response [200]>‘:
                         break
                     im=Image.open(BytesIO(data.content))
                     im.save(file_path+(url.replace(‘/‘,""))[-15:],‘jpeg‘)
                 print("********已下载第%d张"%(i+2))
     else:
         if ispng :
            if os.path.exists(file_path+(url.replace(‘/‘,""))[-15:]):
                print(‘下载完成‘)
                return
            else:
                data=requests.get(url,headers=headers,timeout=60)
                if str(data) == ‘<Response [200]>‘:
                 im=Image.open(BytesIO(data.content))
                 im.save(file_path+(url.replace(‘/‘,""))[-15:],‘png‘)
                print(‘下载完成‘)
         else:
            im=Image.open(BytesIO(data.content))
            im.save(file_path+(url.replace(‘/‘,""))[-15:],‘jpeg‘)
            print(‘下载完成‘)
tag=sys.argv[1]
hot=int(sys.argv[2])
file_path=sys.argv[3]+‘\\Tag\\‘#修改此处即可改变路径
title=tag.replace("\n","").replace(":","").replace("?","").replace("\"","").replace(" ","")
title=title.replace("<","").replace(">","").replace("|","").replace("*","").replace("/","").replace("\\","")
#依据windows目录命名规则
file_path=(file_path+title+str(hot))+"\\"
if not os.path.exists(file_path):
    os.mkdir(file_path)
if not os.path.exists(file_path+‘begin‘):
    f=open(file_path+‘begin‘,"w")
    f.write(‘1‘)
    f.close()
f=open(file_path+‘begin‘,"r")
begin=int(f.read())
for page in range(begin,1001):
    url_save="http://www.pixiv.net/search.php?word=%s&s_mode=s_tag_full&order=date_d&type=illust&p=%d"%(tag,page)
    headers[‘Referer‘]=""
    headers[‘Cookie‘] = cookies
    headers[‘Accept‘] = "text/html"
    wb=requests.get(url_save,headers=headers)
    wb_data=BeautifulSoup(wb.text,‘lxml‘)
    lis=wb_data.body.select(‘li[class="image-item"]‘)
    if len(lis) == 0:
        break
    f=open(file_path+‘begin‘,"w")
    f.write(str(page))
    f.close()
    headers[‘Cookie‘]=""
    headers[‘Accept‘]=‘image/webp,image/*,*/*;q=0.8‘
    os.system("cls")
    print(‘正在下载第%d页...‘%page)
    for li in lis:
        if str(li.ul)!=‘None‘:
            if int(li.ul.i.next_sibling)>=hot:
                os.system("cls")
                print(‘正在下载第%d页...‘%page)
                if li.a[‘class‘][2]==‘multiple‘:
                   getpic(li.img[‘src‘],‘http://www.pixiv.net‘+li.a[‘href‘],‘mul‘)
                else:
                   getpic(li.img[‘src‘],‘http://www.pixiv.net‘+li.a[‘href‘])

这个和上面那个差不多,接受三个参数,标签名,热度(数字),路径,就可以保存图片到路径下,名为标签+热度的文件夹里了,下载速度一般不乐观,主要取决于热度,热度越大,速度越快。

因为不是多线程下载,所有速度不乐观,而且这两段代码我都设定了60秒的request超时限制,所以有可能出现代码动不动就崩溃的现象,一般来说这时只要继续重新运行就好,但是手动点好麻烦,于是,我就写了两个windowsbat来作为程序接口调用他们。通过接受返回码来确定下载是否完成,没完成的话就重新调用程序,所以说脚本真是解放生产力啊,但是还有一个问题,就是程序要支持断点续传,对特辑而言,页面的请求只有一次,且图片数量少,于是只要在下载request每张图之前判断图片是否存在就好,(因为主要时间都消耗在了request和图片写入上,特别是前者),但是对于tag的下载,request页面就不止一次,于是很有必要保存最后一次下载页面的页数。

这是两个脚本

特辑:

@echo off
if not exist Picture md Picture
echo 请选择
echo 1 : 打开每日特辑
echo 2 : 输入特辑号
set /p choose=
if not %choose% == 1 goto else
start http://spotlight.pics/zh
:else
echo 请输入特辑号
set /p number=
:excuteagain
cls
python getpic.py %number% %cd%
if not %errorlevel%==0 goto excuteagain
echo 是否继续下载?输入‘c’继续或输入‘q’退出
set/p continue=
cls
if not %continue%==q goto else
@echo off
if not exist Tag md Tag
echo 请输入标签
set /p tag=
echo 请输入热度(数字)
set /p hot=
:loop
python Tag.py %tag% %hot% %cd%
if not %errorlevel%==0 goto loop
del F:\Tag\%tag%%hot%\begin  

嗯,以上就是全部了,最后说一下,python真的是一门不错的语言,简单,强大,易懂,完美地体现脚本语言的魅力,我觉得非计算机人员比如所各个高校的非计算机专业学生,在学编程时不应该学c,打击积极性,而且学了就忘,应该学python才对。

时间: 2024-10-14 15:12:13

使用python爬取P站图片的相关文章

python爬取B站千万级数据,发现了这些热门UP主的秘密!

Python(发音:英[?pa?θ?n],美[?pa?θɑ:n]),是一种面向对象.直译式电脑编程语言,也是一种功能强大的通用型语言,已经具有近二十年的发展历史,成熟且稳定.它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务.它的语法非常简捷和清晰,与其它大多数程序设计语言不一样,它使用缩进来定义语句. Python支持命令式程序设计.面向对象程序设计.函数式编程.面向切面编程.泛型编程多种编程范式.与Scheme.Ruby.Perl.Tcl等动态语言一样,Python具备垃圾回收

Python 爬取堆糖图片

1 import requests,json,urllib.parse 2 import threading 3 threading_lock=threading.BoundedSemaphore(value=10)#设置最大线程 4 5 def get_page(url): 6 page=requests.get(url) 7 page=page.content 8 page=page.decode('utf-8') 9 return page 10 11 def pages_from_dui

python爬取基础网页图片

python基础爬虫总结 1.爬取信息原理 与浏览器客户端类似,向网站的服务器发送一个请求,该请求一般是url,也就是网址.之后服务器响应一个html页面给客户端,当然也有其他数据类型的信息,这些就是网页内容.我们要做的就是解析这些信息,然后选择我们想要的,将它爬取下来按要求写入到本地. 2. 爬虫基本流程 1.获取网页的响应的信息 这里有两个常用的方法 html = requests.get(url) return html.text 或者 html = urllib.request.urlo

python爬取网站美女图片

今天周五,项目刚刚上线完,有些时间,闲着无聊,继续复习爬虫,这次打算爬取网站的美女图片.得先找到目标,然后目标网站还不会反爬虫,因为自己只是小白,好了开始. 寻找目标,发现了目标,哈哈 http://www.meizitu.com 里面图片按专题分类.先看下页面找出相关源码 页面 源码 即只要抓出来图片集的link跟图片集里面的link对应的jpg就可以了, 可以用beautifulsoup或者正则匹配,我这里用正则匹配需要的link.然后遍历整个网站就可以了 请看源码解释 #!bin/pyth

零基础如何学好python爬虫?之python爬取B站小视频

B 站真是个神奇的网站.找不到资料了,去 B 站逛一逛,保准有你满意的东西. 前几天写了个爬虫,用 path.re.BeautifulSoup 爬取的 B 站 python 视频,如果要爬取多页的话 在最下方循环中 填写好循环的次数就可以了 B 站真是个神奇的网站.找不到资料了,去 B 站逛一逛,保准有你满意的东西. 前几天写了个爬虫,用 path.re.BeautifulSoup 爬取的 B 站 python 视频,如果要爬取多页的话 在最下方循环中 填写好循环的次数就可以了 废话不多说直接上

Python 爬取 B 站,宋智孝李光洙哪个更受宠?

在中国,大家应该都了解<跑男>这个节目吧,跑男这个节目就是引用了韩国的<Running Man>,成员组成包括原六位成员刘在石.池石镇.金钟国.HAHA(河东勋).宋智孝.李光洙 ,以及两位新成员全昭旻.梁世灿 . 自从限韩令发布后,Running man在除B站以外的各大视频网站均下架,所以本文从B站出发,抓取相关视频的所有评论. 由于相关视频非常多,本文选择了最具代表性,点击量观看次数最多的视频. 进入这个页面后开始抓包(https://www.bilibili.com/vid

Python爬取半次元图片[一]

用到模块有requests,BeautifulSoup4,lxml(BeautifulSoup基于这个解析,据说速度会快很多),re(正则ps.只用到了一个compile函数) 介绍下思路: 创建Img文件夹,解析html标题为文件夹名称(创建在Img文件夹下),利用Firefox模块Firehug分析网页(这是需要自己动手分析,不是写代码) 接下来介绍一下使用的函数 re: re.compile("%s"%(往里面填匹配字符就行)) BeautifulSoup: BeautifulS

python 爬取B站视频弹幕信息

获取B站视频弹幕,相对来说很简单,需要用到的知识点有requests.re两个库.requests用来获得网页信息,re正则匹配获取你需要的信息,当然还有其他的方法,例如Xpath.进入你所观看的视频的页面,F12进入开发者工具,选择网络.查找我们需要的信息,发现域名那列有comment.bilibili.com 格式为xml ,文件名即为cid号.点击它后,在右边的消息头中复制请求网址,在浏览器中打开,即可获得视频全部弹幕信息.    代码如下: 1 import requests 2 imp

python 爬取知乎图片

SyntaxError: Non-UTF-8 code starting with '\xbf' in file python-zhihu -v1.2.py on line 34, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details 安装需要的模块 pip install requestspip install PyQuery pip show 命令检查模块是否安装成功(如图所示是成功的)