澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

Python爬虫之爬取美女图片,用Scrapy框架实现漫画

2019-08-03 作者:www.8455.com   |   浏览(61)

  刚刚入门爬虫,今天先对于单个图集进行爬取,过几天再进行翻页爬取。

爬取妹子图(requests BeautifulSoup),

---恢复内容开始---

  刚刚入门爬虫,今天先对于单个图集进行爬取,过几天再进行翻页爬取。

  使用requests库和BeautifulSoup库

  目标网站:妹子图

今天是对于单个图集的爬取,就选择一个进行爬取,我选择的链接为:

首先网站的分析,该网站有一定的反爬虫策略,所以应对就是加入headers(目前是小白,目前不知道具体为毛这样做)

Hostreferer = {
    'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
    'Referer':'http://www.mzitu.com'
}
Picreferer = {
    'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
    'Referer':'http://i.meizitu.net'
}

前一个头作为请求网站,后一个头作为破解盗链使用

获得页面HTML代码

用requests库的get方法,加上Hostreferer

def get_html(url):#获得页面html代码
    req = requests.get(url, headers=Hostreferer)
    html = req.text
    return html

 

获得图集名称以及图集最大页数

分析网页构成如图所示,图集名称包含在h2标签内,且该标签在整个HTML代码里有唯一的class="main-title",

而最大页数只是被span标签包含,无法通过属性来提取。所以提取图集名称采取标签名 属性名一起提取,而最大页数就采取将span标签全部找出,最大页数在span标签中第11位,

 澳门新萄京官方网站 1

def get_page_name(url):#获得图集最大页数和名称
    html = get_html(url)
    soup = BeautifulSoup(html, 'lxml')
    span = soup.findAll('span')
    title = soup.find('h2', class_="main-title")
    return span[10].text, title.text

 

获得图片url链接

  分析页面内容,含有图片链接的img标签中有一个alt属性的值是跟图集名称相同,可以用这个来直接找到这个标签,当然也可以先找到div标签中的class属性是main-inage,再找到img的src属性,这里我就采用第一种方法。

澳门新萄京官方网站 2

def get_img_url(url, name):
    html = get_html(url)
    soup = BeautifulSoup(html, 'lxml')
    img_url = soup.find('img', alt= name)
    return img_url['src']

 

将图片存入本地

  得到图片url链接之后要讲图片存到本地,在请求图片url的时候要加入Picreferer,否则网站会认为你是一个爬虫,会返还给你一个盗链图

该方法传入的参数有3个,第一个是图片url,第二个当前图片的页数,用作创建文件,第三个是图集名称,在存储之前先创建了一个名称是图集名称的文件夹,这样就能将图片存入指定文件夹

def save_img(img_url, count, name):
    req = requests.get(img_url, headers=Picreferer)
    with open(name '/' str(count) '.jpg', 'wb') as f:
        f.write(req.content)

 

完整代码

import requests
from bs4 import BeautifulSoup
import os

Hostreferer = {
    'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
    'Referer':'http://www.mzitu.com'
}
Picreferer = {
    'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
    'Referer':'http://i.meizitu.net'
}

def get_page_name(url):#获得图集最大页数和名称
    html = get_html(url)
    soup = BeautifulSoup(html, 'lxml')
    span = soup.findAll('span')
    title = soup.find('h2', class_="main-title")
    return span[10].text, title.text

def get_html(url):#获得页面html代码
    req = requests.get(url, headers=Hostreferer)
    html = req.text
    return html

def get_img_url(url, name):
    html = get_html(url)
    soup = BeautifulSoup(html, 'lxml')
    img_url = soup.find('img', alt= name)
    return img_url['src']

def save_img(img_url, count, name):
    req = requests.get(img_url, headers=Picreferer)
    with open(name '/' str(count) '.jpg', 'wb') as f:
        f.write(req.content)

def main():
    old_url = "http://www.mzitu.com/123114"
    page, name = get_page_name(old_url)
    os.mkdir(name)
    for i in range(1, int(page) 1):
        url = old_url   "/"   str(i)
        img_url = get_img_url(url, name)
        #print(img_url)
        save_img(img_url, i, name)
        print('保存第'   str(i)   '张图片成功')
main()

 

  在main方法中先请求到图集的名称和最大页数,并且使用名称创建一个文件夹来存储图片。再从1到最大页数做一个for循环,

然后图片的每一页是     图集首页  / 当前页数,得到含有图片内容的url链接,后面就可以将得到图片存入本地。

 

爬取结果

澳门新萄京官方网站 3

 

  文件夹名称即为图集名称,内部图片以页数作为文件名。

 

 

 

#目前就先进行一个图集的爬取,后面爬取多个图集我会尽快更新,有什么问题可以在下方评论,欢迎大家讨论。

BeautifulSoup), ---恢复内容开始--- 刚刚入门爬虫,今天先对于单个图集进行爬取,过几天再进行翻页爬取。 使用request...

需求:最近对python爬虫感兴趣,于是学习了下python爬虫并找了个网站练习,练习网址:http://www.mmjpg.com,其中每一套图都是一张一个页面,存一套图如果是手动得点翻几十个页面,但如果使用爬虫的话,就很方便了,轻轻松松就可以把美女存到硬盘了。

澳门新萄京官方网站 4

其实从接触python到现在已经快大半年了,中间看过不少的视频,也跟着别人的教程写过不少东西,但是到现在还感觉没有入门。其实中间也明白是为什么,就好比小学生上课一样,上课认真听,认真做笔记,可是下了课之后就从来不看笔记,也从来不写作业。上课一听就懂,自己一写啥都不会,我相信很多人跟我现在是一样的感觉,所以现在创建这个作业集,一来是想鞭策自己真真正正的写点东西,二来也是希望广大的读者老师能够给我批改批改作业,大家相互学习共同进步。

  使用requests库和BeautifulSoup库

实验环境:

  • Windows 10,Python 2.7.6,Pycharm

14.jpg

好了,现在开始进入正题。

  目标网站:妹子图

1.确定目标网址

澳门新萄京官方网站 5

www.mmjpg.com

在之前一篇抓取漫画图片的文章里,通过实现一个简单的Python程序,遍历所有漫画的url,对请求所返回的html源码进行正则表达式分析,来提取到需要的数据。

第一弹 邪恶集

澳门新萄京官方网站 6

dd01.jpg

为什么会想到爬邪恶集呢?是因为之前看到过msq3大神写的邪恶集爬虫,所以自己也想照着他的写一写。不过碍于自己水平有限,msq3用了面向对象编程,其实我还不太会。所以就用自己的方法写了。写的不好的地方还请各位老师多指点指点。

今天是对于单个图集的爬取,就选择一个进行爬取,我选择的链接为:

2.分析网页URL变化

通过打开不同页数的页面内容后发现
第二页:http://www.mmjpg.com/home/2
第三页:http://www.mmjpg.com/home/3
每当我们点击一个页面,url改变的是最后面的数字,因此我们需要找到总页数的html代码,才能对其进行爬虫翻页

本篇文章,通过 scrapy 框架来实现相同的功能。scrapy 是一个为了爬取网站数据,提取结构性数据而编写的应用框架。关于框架使用的更多详情可浏览官方文档,本篇文章展示的是爬取漫画图片的大体实现过程。

第一步 请求页面

澳门新萄京官方网站 7

get_page函数请求网页

get_page函数专门用于请求网页的,这里需要注意的地方是网页的编码格式不是通常的utf8,所以要指定网页编码是gb2312,不然返回的网页无法显示中文。

澳门新萄京官方网站 8

Paste_Image.png

但是我在这里还是遇到了一个小问题。比如说

澳门新萄京官方网站 9

Paste_Image.png

澳门新萄京官方网站 10

Paste_Image.png

标题没办法显示,有没有大神知道是为什么?

首先网站的分析,该网站有一定的反爬虫策略,所以应对就是加入headers(目前是小白,目前不知道具体为毛这样做)

3.分析网页源代码

通过审查网页元素定位到了总页数的html元素:<a href="/home/79" class="last">最旧</a> 由此可以得出该网址的总页数为79页,接下来便可对其进行提取

scrapy环境配置

第二步 获取所有漫画的url

澳门新萄京官方网站 11

Paste_Image.png

从图中我们可以看到一共有19页661部漫画,所有我们只要写个列表生成式,这样就可以把所有19页的url放进一个列表中然后依次请求每一页的url就能获取所有漫画的url了。很简单吧!

澳门新萄京官方网站 12

19页url

我们可以看到漫画的链接在class="piclist listcon"的列表中,但是链接是不完整的,我们必须继续拼出完整的url才行。

澳门新萄京官方网站 13

Paste_Image.png

get_comic_url函数就是用来获取所有漫画的url并且将其保存到comic_list的列表中。一共661个url。

澳门新萄京官方网站 14

获取所有漫画url

Beautifulsoup我就不多说了,了解爬虫的应该都知道。这里我们用到了parse.urljoin()函数(from urllib import parse)这个函数呢是用来拼接url的(我只知道这么多,(⊙﹏⊙)b,感觉自己好水。。。会用就好了。)

Hostreferer = {
    'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
    'Referer':'http://www.mzitu.com'
}
Picreferer = {
    'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
    'Referer':'http://i.meizitu.net'
}

4.引入所需要的库

import os
import re
import urllib2                                                                                                          
from lxml import html     

安装

首先是 scrapy 的安装,博主用的是Mac系统,直接运行命令行:

pip install Scrapy

对于html节点信息的提取使用了 Beautiful Soup 库,大概的用法可见之前的一篇文章,直接通过命令安装:

pip install beautifulsoup4

对于目标网页的 Beautiful Soup 对象初始化需要用到 html5lib 解释器,安装的命令:

pip install html5lib

安装完成后,直接在命令行运行命令:

scrapy

可以看到如下输出结果,这时候证明scrapy安装完成了。

Scrapy 1.2.1 - no active project

Usage:
  scrapy <command> [options] [args]

Available commands:
  bench         Run quick benchmark test
  commands      
  fetch         Fetch a URL using the Scrapy downloader
  genspider     Generate new spider using pre-defined templates
  runspider     Run a self-contained spider (without creating a project)
  settings      Get settings values
  ...
第三步 解析漫画详情页获取漫画标题和图片的链接

上一步呢我们获取了所有漫画的url保存在了一个list当中,现在我们挨个请求comic_list中的url。
通过观察网页我们发现我们可以从网页上直接看到漫画一共有多少页(page_num),也就是多少张图片。
(上一章下一章点开之后会发现跳到了另外一部漫画,所有我们不用在意,这里的一部漫画很短)

澳门新萄京官方网站 15

Paste_Image.png

澳门新萄京官方网站 16

获取一共多少页

澳门新萄京官方网站 17

获取一共多少页

正则是用来提取数字。

然后我们一页一页的点击观察url的变化会发现除了第一页的url就是漫画的url外,其他从第二页一直到最后的url都是有规律的

澳门新萄京官方网站 18

第一页url

澳门新萄京官方网站 19

第二页url

澳门新萄京官方网站 20

第三页url

澳门新萄京官方网站 21

第十二页url

找到规律这就简单了,跟先前构造漫画url差不多。我们构造构造除了第一页外的其他页数的url

澳门新萄京官方网站 22

每一页的url

先去掉html,在加上_{}.html。
这样我们就可以获取漫画的标题(用来作为文件夹的名字)和漫画每一张图片的链接。方便之后的下载和保存。

前一个头作为请求网站,后一个头作为破解盗链使用

5.获取网页源代码

def get_source_page(self, url):
    '''
    返回经过lxml.html.fromstring 模块处理的<Element html at 0x36e8278>
    可以用 XPath 来过滤数据
    '''
    try:
        response = urllib2.urlopen(url, timeout=3).read()
        selector = html.fromstring(response)
    except:
        selector = None
    finally:
        return selector

项目创建

通过命令行在当前路径下创建一个名为 Comics 的项目

scrapy startproject Comics

创建完成后,当前目录下出现对应的项目文件夹,可以看到生成的Comics文件结构为:

|____Comics
| |______init__.py
| |______pycache__
| |____items.py
| |____pipelines.py
| |____settings.py
| |____spiders
| | |______init__.py
| | |______pycache__
|____scrapy.cfg

Ps. 打印当前文件结构命令为:

find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'

每个文件对应的具体功能可查阅官方文档,本篇实现对这些文件涉及不多,所以按下不表。

第四步 保存漫画

保存漫画分两步,首先是创建文件夹,其次是保存。

澳门新萄京官方网站 23

创建文件夹

其中的filename就是第三步中获取的漫画标题。
保存图片我们用到了urllib库中request.urlretrieve()如果直接保存的话可能会报403的错。所以我们需要把User-agent加进去。

澳门新萄京官方网站 24

保存图片

我们用图片链接的后面四位(如这里是dd12)作为每一张图片的名字(title)用于区分图片

澳门新萄京官方网站 25

图片链接

这样的话我们就可以把所有的漫画都爬下来啦。是不是很简单!

澳门新萄京官方网站 26

Paste_Image.png

澳门新萄京官方网站 27

Paste_Image.png

澳门新萄京官方网站 28

Paste_Image.png

完整的代码在我的GitHub上,喜欢的就赏个星星。

获得页面HTML代码

6.获取总页数

def get_sum_page(self, url):
    selector = self.get_source_page(url)
    '''使用xpath提取网页中总页数的元素'''
    sum_page = selector.xpath('//div[@class="page"]//a[last()]/@href')[0].split('/')[-1]
    return sum_page

创建Spider类

创建一个用来实现具体爬取功能的类,我们所有的处理实现都会在这个类中进行,它必须为 scrapy.Spider 的子类。

Comics/spiders 文件路径下创建 comics.py 文件。

comics.py 的具体实现:

#coding:utf-8

import scrapy

class Comics(scrapy.Spider):

    name = "comics"

    def start_requests(self):
        urls = ['http://www.xeall.com/shenshi']
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        self.log(response.body);

自定义的类为scrapy.Spider的子类,其中的name属性为该爬虫的唯一标识,作为scrapy爬取命令的参数。其他方法的属性后续再解释。

第二弹 风之动漫全站爬虫

澳门新萄京官方网站 29

女帝

风之动漫相比较邪恶集呢稍微有点难度,不过也是大同小异,跟着我的步骤,我相信你可以看明白。

用requests库的get方法,加上Hostreferer

7.用总页数来组合拼接出所有页面的url,并返回包含所有url的list

def get_all_page_urls(self, sumpage):
    urls = []
    baseurl = 'http://www.mmjpg.com/home/'
    ul = baseurl.split('/')
    for page in range(1, int(sumpage)   1):
        ul[-1] = str(page)
        url = '/'.join(ul)
        urls.append(url)
    return urls

运行

创建好自定义的类后,切换到Comics路径下,运行命令,启动爬虫任务开始爬取网页。

scrapy crawl comics

打印的结果为爬虫运行过程中的信息,和目标爬取网页的html源码。

2016-11-26 22:04:35 [scrapy] INFO: Scrapy 1.2.1 started (bot: Comics)
2016-11-26 22:04:35 [scrapy] INFO: Overridden settings: {'ROBOTSTXT_OBEY': True, 'BOT_NAME': 'Comics', 'NEWSPIDER_MODULE': 'Comics.spiders', 'SPIDER_MODULES': ['Comics.spiders']}
2016-11-26 22:04:35 [scrapy] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.logstats.LogStats']
 ...

此时,一个基本的爬虫创建完成了,下面是具体过程的实现。

第一步 先分析网页

打开风之动漫拉到最下面我们可以看到在网站的最下面有一个网站地图

澳门新萄京官方网站 30

网站地图

打开之后呢我们可以看到全站的所有漫画都在里面。

澳门新萄京官方网站 31

所有漫画

这下就简单多了,爬取map页的所有漫画的url,然后放入一个list中,依次请求list中漫画的url,从而爬取所有的漫画。
这里的漫画跟邪恶集不同的是,每一部漫画都有很多话。每一话又有很多的图片。所有在处理的时候稍微有点麻烦。

def get_html(url):#获得页面html代码
    req = requests.get(url, headers=Hostreferer)
    html = req.text
    return html

8.获取每个图集的链接

'''由于首页图片点击进去之后还有图片,因此首页图片是一个图集链接,所以得先获取图集链接,进而获取里面的所有图片,分析网页代码得知,可对其连接进行提取,并同样返回一个list'''
def get_page_links(self, urls):
    page_links = []
    for url in urls:
        try:
            selector = self.get_source_page(url)
            lis = selector.xpath('//div[@class="pic"]//li/a/@href')
        except:
            continue
        for li in lis:
            page_links.append(li)
    return page_links

爬取漫画图片

第二步 获取漫画每一话的url

澳门新萄京官方网站 32

漫画每一话

获取漫画每一话的标题和对应的url,保存到字典comic_chapter_url_dict

澳门新萄京官方网站 33

Paste_Image.png

澳门新萄京官方网站 34

Paste_Image.png

如果不明白什么是****kwargs的,请自行百度“什么是*args和****kwargs”,写这个爬虫之前我也不懂,写完之后一知半解。我的理解就是*args呢表示可以把列表当参数传给函数进行处理,****kwargs**表示可以把字典当做参数传给函数进行处理。不知道怎么用的可以看看我的爬虫源码。

 

9.获取图片的src属性

def get_pic_link(self, url):
    try:
        selector = self.get_source_page(url)
        src = selector.xpath('//div[@id="content"]/a/img/@src')[0]
    except:
        src = None
    finally:
        return src

起始地址

爬虫的起始地址为:

http://www.xeall.com/shenshi

我们主要的关注点在于页面中间的漫画列表,列表下方有显示页数的控件。如下图所示

澳门新萄京官方网站 35

1.jpg

爬虫的主要任务是爬取列表中每一部漫画的图片,爬取完当前页后,进入下一页漫画列表继续爬取漫画,依次不断循环直至所有漫画爬取完毕。

起始地址的url我们放在了start_requests函数的urls数组中。其中start_requests是重载了父类的方法,爬虫任务开始时会执行到这个方法。

start_requests方法中主要的执行在这一行代码:请求指定的url,请求完成后调用对应的回调函数self.parse

scrapy.Request(url=url, callback=self.parse)

对于之前的代码其实还有另一种实现方式:

#coding:utf-8

import scrapy

class Comics(scrapy.Spider):

    name = "comics"
    start_urls = ['http://www.xeall.com/shenshi']

    def parse(self, response):
        self.log(response.body);

start_urls是框架中提供的属性,为一个包含目标网页url的数组,设置了start_urls的值后,不需要重载start_requests方法,爬虫也会依次爬取start_urls中的地址,并在请求完成后自动调用parse作为回调方法。

不过为了在过程中方便调式其它的回调函数,demo中还是使用了前一种实现方式。

第三步 解析每一话,爬取所有图片

最难的部分来了。
首先通过F12 我们可以看到图片的链接在一个id="mhpic"的img标签中

澳门新萄京官方网站 36

图片链接

如果直接爬这个标签是什么也爬不到的。因为图片的src是通过js加载的,直接爬是不行。
其次我们该如何创建文件夹才能把图片保存到对应的漫画对应的一话中呢?
最后我们该如何翻页呢?

澳门新萄京官方网站 37

翻页

风之动漫不像邪恶集直接告诉我们一共有多少页。风之动漫如果不翻到最后一页的话是不知道一共有多少页的。
带着这三个问题我们继续往下看。
解决第一个问题我们使用selenium PhantomJS就可以了,selenium是自动化测试框架,可以模拟浏览器操作,PhantomJS是一个无界面的浏览器。我相信大家应该都知道。如果不懂的话推荐大家看一下崔庆才老师的用selenium模拟浏览器抓取淘宝商品美食信息我也是看这个才明白的。

澳门新萄京官方网站 38

获取图片链接

html = brower.page_source就是js加载之后的网页,这个时候我们用正则匹配出图片的链接就可以了。
接下来我们创建文件夹

澳门新萄京官方网站 39

文件夹名

我们可以看到在“位置”之中正好有我们要的文件夹名字(旋风管家 旋风管家561话)这就简单了。

澳门新萄京官方网站 40

文件夹名

使用正则表达式匹配出我们想要的字符分别保存在path1和path2中作为路径,然后调用make_file()函数创建文件

澳门新萄京官方网站 41

make_file()

最后轮到翻页。这个也挺简单的,我们只要在爬取每一页的时候判断一下这一页有没有字符“下一頁”,如果有就有下一页如果没有就是最后一页。停止爬取。

澳门新萄京官方网站 42

翻页

每一页的url也是有规律的形如index_1,index_2,index_3。。。构造一下就出来了,依次请求依次爬取每一张图片。

澳门新萄京官方网站 43

结果1

澳门新萄京官方网站 44

结果2

澳门新萄京官方网站 45

结果4

澳门新萄京官方网站 46

结果4

听起来是不是挺简单的?其实实现起来还是需要自己多动动脑筋的。大家可以根据我的思路先实现一下,不明白的地方可以参考一下我的源码
两个爬虫虽然可以实现漫画的爬取,但是呢爬虫其实写的很粗糙,有很多地方可以改善。比如说,很多异常处理没有加进去在保存图片的时候经常就会遇到这样的报错

澳门新萄京官方网站 47

报错

网站没有反爬,如果有反爬我们又该怎么处理呢?这么多漫画爬起来会很慢,我们可以加入多进程和多线程。最后呢,我觉得可以用到面向对象来写可能会更好一点,但是碍于自己水平有限,还不太会用面向对象方法。

最后希望能够帮助那些比我还小白的小白,也希望各位大神看过之后能够指点一二,不胜感激。
两个爬虫的GitHub地址

获得图集名称以及图集最大页数

10.创建文件夹并用图集名进行命名

def mk_pic_dir(self, dirname):
    path = dirname
    if not os.path.exists(path):
        os.mkdir(path)
    return path

爬取漫画url

从起始网页开始,首先我们要爬取到每一部漫画的url。

分析网页构成如图所示,图集名称包含在h2标签内,且该标签在整个HTML代码里有唯一的class="main-title",

11.进入所有图集,并下载所有图片

def download_all_pic(self, page_links):
    for page_link in page_links:
        try:
            selector = self.get_source_page(page_link)
            album_title = selector.xpath('//div[@class="article"]/h2/text()')[0]
            sum_pic = selector.xpath('//div[@id="page"]/a[last()-1]/text()')[0]
            path = self.mk_pic_dir(album_title)
        except:
            continue
        for pic in range(1, int(sum_pic)   1):
            try:
                print u'正在下载-->'   album_title   u'-->第'   str(pic)   u'张美图...'
                pic_link = page_link   '/'   str(pic)
                src = self.get_pic_link(pic_link)
                filename = '%s.jpg' % (pic)
            except:
                continue
            else:
                try:
                    '''增加打开图片链接时的头部referer属性'''
                    req = urllib2.Request(src)
                    req.add_header('Referer', 'http://img.mmjpg.com/')
                    '''写入文件'''
                    with open(path   '/'   filename, 'wb') as fp:
                        fp.write(urllib2.urlopen(src, timeout=3).read())
                 except:
                    continue

当前页漫画列表

起始页为漫画列表的第一页,我们要从当前页中提取出所需信息,动过实现回调parse方法。

在开头导入BeautifulSoup

from bs4 import BeautifulSoup

请求返回的html源码用来给BeautifulSoup初始化。

def parse(self, response):
    content = response.body;
    soup = BeautifulSoup(content, "html5lib")

初始化指定了html5lib解释器,若没安装这里会报错。BeautifulSoup初始化时若不提供指定解释器,则会自动使用自认为匹配的最佳解释器,这里有个坑,对于目标网页的源码使用默认最佳解释器为lxml,此时解析出的结果会有问题,而导致无法进行接下来的数据提取。所以当发现有时候提取结果又问题时,打印soup看看是否正确。

查看html源码可知,页面中显示漫画列表的部分为类名为listconul标签,通过listcon类能唯一确认对应的标签

澳门新萄京官方网站 48

2.jpg

提取包含漫画列表的标签

listcon_tag = soup.find('ul', class_='listcon')

上面的find方法意为寻找classlistconul标签,返回的是对应标签的所有内容。

在列表标签中查找所有拥有href属性的a标签,这些a标签即为每部漫画对应的信息。

com_a_list = listcon_tag.find_all('a', attrs={'href': True})

然后将每部漫画的href属性合成完整能访问的url地址,保存在一个数组中。

comics_url_list = []
base = 'http://www.xeall.com'
    for tag_a in com_a_list:
        url = base   tag_a['href']
        comics_url_list.append(url)

此时comics_url_listPython爬虫之爬取美女图片,用Scrapy框架实现漫画的爬取。数组即包含当前页每部漫画的url。

而最大页数只是被span标签包含,无法通过属性来提取。所以提取图集名称采取标签名 属性名一起提取,而最大页数就采取将span标签全部找出,最大页数在span标签中第11位,

12.大功告成,运行代码

澳门新萄京官方网站 49

编辑器执行过程

澳门新萄京官方网站 50

以图集名命名的文件夹

澳门新萄京官方网站 51

对应图集里面的所有图片

本实验的完整代码在Github上,欢迎fork

下一页列表

Python爬虫之爬取美女图片,用Scrapy框架实现漫画的爬取。看到列表下方的选择页控件,我们可以通过这个地方来获取到下一页的url。

澳门新萄京官方网站 52

3.jpg

获取选择页标签中,所有包含href属性的a标签

page_tag = soup.find('ul', class_='pagelist')
page_a_list = page_tag.find_all('a', attrs={'href': True})

这部分源码如下图,可看到,所有的a标签中,倒数第一个代表末页的url,倒数第二个代表下一页的url,因此,我们可以通过取page_a_list数组中倒数第二个元素来获取到下一页的url。

澳门新萄京官方网站 53

5.jpg

但这里需要注意的是,若当前为最后一页时,不需要再取下一页。那么如何判断当前页是否是最后一页呢?

可以通过select控件来判断。通过源码可以判断,当前页对应的option标签会具有selected属性,下图为当前页为第一页

澳门新萄京官方网站 54

4.jpg

下图为当前页为最后一页

澳门新萄京官方网站 55

6.jpg

通过当前页数与最后一页页数做对比,若相同则说明当前页为最后一页。

select_tag = soup.find('select', attrs={'name': 'sldd'})
option_list = select_tag.find_all('option')

last_option = option_list[-1]
current_option = select_tag.find('option' ,attrs={'selected': True})

is_last = (last_option.string == current_option.string)

当前不为最后一页,则继续对下一页做相同的处理,请求依然通过回调parse方法做处理

if not is_last:
    next_page = 'http://www.xeall.com/shenshi/'   page_a_list[-2]['href']
    if next_page is not None:
        print('n------ parse next page --------')
        print(next_page)
        yield scrapy.Request(next_page, callback=self.parse)

通过同样的方式依次处理每一页,直到所有页处理完成。

 澳门新萄京官方网站 56

爬取漫画图片

parse方法中提取到当前页的所有漫画url时,就可以开始对每部漫画进行处理。

在获取到comics_url_list数组的下方加上下面代码:

for url in comics_url_list:
    yield scrapy.Request(url=url, callback=self.comics_parse)

对每部漫画的url进行请求,回调处理方法为self.comics_parsecomics_parse方法用来处理每部漫画,下面为具体实现。

def get_page_name(url):#获得图集最大页数和名称
    html = get_html(url)
    soup = BeautifulSoup(html, 'lxml')
    span = soup.findAll('span')
    title = soup.find('h2', class_="main-title")
    return span[10].text, title.text

当前页图片

首相将请求返回的源码构造一个BeautifulSoup,和前面基本一致

def comics_parse(self, response):
    content = response.body;
    soup = BeautifulSoup(content, "html5lib")

澳门新萄京官方网站,提取选择页控件标签,页面显示和源码如下所示

澳门新萄京官方网站 57

7.jpg

澳门新萄京官方网站 58

8.jpg

提取classpagelistul标签

page_list_tag = soup.find('ul', class_='pagelist')

查看源码可以看到当前页的li标签的class属性thisclass,以此获取到当前页页数

current_li = page_list_tag.find('li', class_='thisclass')
page_num = current_li.a.string

当前页图片的标签和对应源码

澳门新萄京官方网站 59

9.jpg

澳门新萄京官方网站 60

10.jpg

获取当前页图片的url,以及漫画的标题。漫画标题之后用来作为存储对应漫画的文件夹名称。

li_tag = soup.find('li', id='imgshow')
img_tag = li_tag.find('img')

img_url = img_tag['src']
title = img_tag['alt']

 

保存到本地

当提取到图片url时,便可通过url请求图片并保存到本地

self.save_img(page_num, title, img_url)

定义了一个专门用来保存图片的方法save_img,具体完整实现如下

# 先导入库
import os
import urllib
import zlib

def save_img(self, img_mun, title, img_url):
    # 将图片保存到本地
    self.log('saving pic: '   img_url)

    # 保存漫画的文件夹
    document = '/Users/moshuqi/Desktop/cartoon'

    # 每部漫画的文件名以标题命名
    comics_path = document   '/'   title
    exists = os.path.exists(comics_path)
    if not exists:
        self.log('create document: '   title)
        os.makedirs(comics_path)

    # 每张图片以页数命名
    pic_name = comics_path   '/'   img_mun   '.jpg'

    # 检查图片是否已经下载到本地,若存在则不再重新下载
    exists = os.path.exists(pic_name)
    if exists:
        self.log('pic exists: '   pic_name)
        return

    try:
        user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
        headers = { 'User-Agent' : user_agent }

        req = urllib.request.Request(img_url, headers=headers)
        response = urllib.request.urlopen(req, timeout=30)

        # 请求返回到的数据
        data = response.read()

        # 若返回数据为压缩数据需要先进行解压
        if response.info().get('Content-Encoding') == 'gzip':
            data = zlib.decompress(data, 16   zlib.MAX_WBITS)

        # 图片保存到本地
        fp = open(pic_name, "wb")
        fp.write(data)
        fp.close

        self.log('save image finished:'   pic_name)

    except Exception as e:
        self.log('save image error.')
        self.log(e)

函数主要用到3个参数,当前图片的页数,漫画的名称,图片的url。

图片会保存在以漫画名称命名的文件夹中,若不存在对应文件夹,则创建一个,一般在获取第一张图时需要自主创建一个文件夹。

document为本地指定的文件夹,可自定义。

每张图片以页数.jpg的格式命名,若本地已存在同名图片则不再进行重新下载,一般用在反复开始任务的情况下进行判断以避免对已存在图片进行重复请求。

请求返回的图片数据是被压缩过的,可以通过response.info().get('Content-Encoding')的类型来进行判断。压缩过的图片要先经过zlib.decompress解压再保存到本地,否则图片打不开。

大体实现思路如上,代码中也附上注释了。

获得图片url链接

下一页图片

和在漫画列表界面中的处理方式类似,在漫画页面中我们也需要不断获取下一页的图片,不断的遍历直至最后一页。

澳门新萄京官方网站 61

11.jpg

当下一页标签的href属性为#时为漫画的最后一页

a_tag_list = page_list_tag.find_all('a')
next_page = a_tag_list[-1]['href']
if next_page == '#':
    self.log('parse comics:'   title   'finished.')
else:
    next_page = 'http://www.xeall.com/shenshi/'   next_page
    yield scrapy.Request(next_page, callback=self.comics_parse)

若当前为最后一页,则该部漫画遍历完成,否则继续通过相同方式处理下一页

yield scrapy.Request(next_page, callback=self.comics_parse)

  分析页面内容,含有图片链接的img标签中有一个alt属性的值是跟图集名称相同,可以用这个来直接找到这个标签,当然也可以先找到div标签中的class属性是main-inage,再找到img的src属性,这里我就采用第一种方法。

运行结果

大体的实现基本完成,运行起来,可以看到控制台打印情况

澳门新萄京官方网站 62

12.jpg

本地文件夹保存到的图片

澳门新萄京官方网站 63

13.jpg

scrapy框架运行的时候使用了多线程,能够看到多部漫画是同时进行爬取的。

目标网站资源服务器感觉比较慢,会经常出现请求超时的情况。跑的时候请耐心等待。:)

澳门新萄京官方网站 64

最后

本文介绍的只是scrapy框架非常基本的用法,还有各种很细节的特性配置,如使用FilesPipelineImagesPipeline来保存下载的文件或者图片;框架本身自带了个XPath类用来对网页信息进行提取,这个的效率要比BeautifulSoup高;也可以通过专门的item类将爬取的数据结果保存作为一个类返回。具体请查阅官网。

最后附上完整Demo源码,如果我告诉你其实目标网站是福利你会给个star么?-_-

完。

def get_img_url(url, name):
    html = get_html(url)
    soup = BeautifulSoup(html, 'lxml')
    img_url = soup.find('img', alt= name)
    return img_url['src']

 

将图片存入本地

  得到图片url链接之后要讲图片存到本地,在请求图片url的时候要加入Picreferer,否则网站会认为你是一个爬虫,会返还给你一个盗链图

该方法传入的参数有3个,第一个是图片url,第二个当前图片的页数,用作创建文件,第三个是图集名称,在存储之前先创建了一个名称是图集名称的文件夹,这样就能将图片存入指定文件夹

def save_img(img_url, count, name):
    req = requests.get(img_url, headers=Picreferer)
    with open(name '/' str(count) '.jpg', 'wb') as f:
        f.write(req.content)

 

爬取一个图集完整代码

import requests
from bs4 import BeautifulSoup
import os

Hostreferer = {
    'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
    'Referer':'http://www.mzitu.com'
}
Picreferer = {
    'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
    'Referer':'http://i.meizitu.net'
}

def get_page_name(url):#获得图集最大页数和名称
    html = get_html(url)
    soup = BeautifulSoup(html, 'lxml')
    span = soup.findAll('span')
    title = soup.find('h2', class_="main-title")
    return span[10].text, title.text

def get_html(url):#获得页面html代码
    req = requests.get(url, headers=Hostreferer)
    html = req.text
    return html

def get_img_url(url, name):
    html = get_html(url)
    soup = BeautifulSoup(html, 'lxml')
    img_url = soup.find('img', alt= name)
    return img_url['src']

def save_img(img_url, count, name):
    req = requests.get(img_url, headers=Picreferer)
    with open(name '/' str(count) '.jpg', 'wb') as f:
        f.write(req.content)

def main():
    old_url = "http://www.mzitu.com/123114"
    page, name = get_page_name(old_url)
    os.mkdir(name)
    for i in range(1, int(page) 1):
        url = old_url   "/"   str(i)
        img_url = get_img_url(url, name)
        #print(img_url)
        save_img(img_url, i, name)
        print('保存第'   str(i)   '张图片成功')
main()

 

  在main方法中先请求到图集的名称和最大页数,并且使用名称创建一个文件夹来存储图片。再从1到最大页数做一个for循环,

然后图片的每一页是     图集首页  / 当前页数,得到含有图片内容的url链接,后面就可以将得到图片存入本地。

 

爬取结果

澳门新萄京官方网站 65

 

  文件夹名称即为图集名称,内部图片以页数作为文件名。

 

 

 

下面准备开始多个页面的爬取,先将前面爬取一个图集的方法进行封装

爬取一个图集

在进行爬取一个图集前先加入一个方法,在爬取图集名称的时候,由于名称的字符不限,所以可能出现含有文件夹中不能出现的一些字符,例如:/ : ? < > 等

所以需要将前面的代码进行修改,加入一个rename方法,将这些字符换成可行的字符。(在这里我就直接将这些字符去掉)

这里采用re库,将name中含有的非法字符换成空,可以看做直接去掉。

import re
def rename(name):
    rstr = r'[/\:*?<>|]'
    new_name = re.sub(rstr, "", name)
    return new_name

def save_one_atlas(old_url):
    page, name = get_page_name(old_url)
    new_name = rename(name)
    os.mkdir(new_name)

    print("图集--"   name   "--开始保存")
    for i in range(1, int(page) 1):
        url = old_url   "/"   str(i)
        img_url = get_img_url(url, name)
        # print(img_url)
        save_img(img_url, i, name)
        print('正在保存第'   str(i)   '张图片')
    print("图集--"   name   "保存成功")

 

爬取一整页图集

def get_atlas_list(url):
    req = requests.get(url, headers=Hostreferer)
    soup = BeautifulSoup(req.text, 'lxml')
    atlas = soup.find_all(attrs={'class':'lazy'})
    atlas_list = []
    for atla in atlas:
        atlas_list.append(atla.parent['href'])
    return atlas_list

分析一个页面中的url链接,发现如果找 target="_blank" 这一属性,则会产生很多多余的链接,所以我直接从字标签入手找到属性 class="lazy"的img标签,然后再在寻找到img标签的父标签中的href

def save_one_page(start_url):
    atlas_url = get_atlas_list(start_url)
    for url in atlas_url:
        save_one_atlas(url)

将爬取一整夜图集进行封装,方便后续的翻页爬取

 

翻页爬取

分析页面url,发现每一页均是初始网址 page/ 页数/

第一页是初始网址,但是页数为1的链接也是直接进入第一页,所以所有页的url就可以用以上通式改变页数进行遍历。

 

start_url = "http://www.mzitu.com/"
    for count in range(1, 3):
        url = start_url   "page/"   str(count)  "/"
        save_one_page(url)

 

这里作为测试,所以只爬取前两页图集。改变range内的参数,即可改变爬取页数。

 

完整代码

澳门新萄京官方网站 66澳门新萄京官方网站 67

 1 import requests
 2 from bs4 import BeautifulSoup
 3 import os
 4 import re
 5 
 6 Hostreferer = {
 7     'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
 8     'Referer':'http://www.mzitu.com'
 9 }
10 Picreferer = {
11     'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
12     'Referer':'http://i.meizitu.net'
13 }
14 
15 def get_page_name(url):#获得图集最大页数和名称
16     html = get_html(url)
17     soup = BeautifulSoup(html, 'lxml')
18     span = soup.findAll('span')
19     title = soup.find('h2', class_="main-title")
20     return span[10].text, title.text
21 
22 def get_html(url):#获得页面html代码
23     req = requests.get(url, headers=Hostreferer)
24     html = req.text
25     return html
26 
27 def get_img_url(url, name):
28     html = get_html(url)
29     soup = BeautifulSoup(html, 'lxml')
30     img_url = soup.find('img', alt= name)
31     return img_url['src']
32 
33 def save_img(img_url, count, name):
34     req = requests.get(img_url, headers=Picreferer)
35     new_name = rename(name)
36     with open(new_name '/' str(count) '.jpg', 'wb') as f:
37         f.write(req.content)
38 
39 def rename(name):
40     rstr = r'[/\:*?<>|]'
41     new_name = re.sub(rstr, "", name)
42     return new_name
43 
44 def save_one_atlas(old_url):
45     page, name = get_page_name(old_url)
46     new_name = rename(name)
47     os.mkdir(new_name)
48     
49     print("图集--"   name   "--开始保存")
50     for i in range(1, int(page) 1):
51         url = old_url   "/"   str(i)
52         img_url = get_img_url(url, name)
53         # print(img_url)
54         save_img(img_url, i, name)
55         print('正在保存第'   str(i)   '张图片')
56     print("图集--"   name   "保存成功")
57 
58 
59 def get_atlas_list(url):
60     req = requests.get(url, headers=Hostreferer)
61     soup = BeautifulSoup(req.text, 'lxml')
62     atlas = soup.find_all(attrs={'class':'lazy'})
63     atlas_list = []
64     for atla in atlas:
65         atlas_list.append(atla.parent['href'])
66     return atlas_list
67 
68 def save_one_page(start_url):
69     atlas_url = get_atlas_list(start_url)
70     for url in atlas_url:
71         save_one_atlas(url)
72 
73 
74 if __name__ == '__main__':
75     start_url = "http://www.mzitu.com/"
76     for count in range(1, 3):
77         url = start_url   "page/"   str(count)  "/"
78         save_one_page(url)
79     print("爬取完成")

View Code

 

这个程序能够爬取图片,但是效率太低,正在学习多进程,希望之后可以提高该程序的爬取效率。

我爬了3个多G的图片花了我接近4个小时,足以证明效率是真的低。

并且在爬取过程中出现一个问题,提示 你的主机中的软件中止了一个已建立的连接 ,这个问题还未找到解决方法,也未找明产生的具体原因。

这是我写的第一篇较长的博客,还有很多未完善的地方,希望大家见谅。

 

本文由澳门新萄京官方网站发布于www.8455.com,转载请注明出处:Python爬虫之爬取美女图片,用Scrapy框架实现漫画

关键词: