Python3 大型网络爬虫实战 003 — scrapy 大型静态图片网站爬虫项目实战 — 实战:爬取 169美女图片网 高清图片

news/2024/12/22 22:46:07/

原博文链接:http://www.aobosir.com/blog/2016/12/26/python3-large-web-crawler-169bb-com-HD-beautiful-pictures/


    • 开发环境
    • 观察网页 和 网页源代码
    • 写程序
      • 下载高清图片
    • 下载 169美女图片网 的所有西洋美女的图片
    • 防反爬技术
    • 搞定

开发环境

  • Python第三方库:lxml、Twisted、pywin32、scrapy
  • Python 版本:python-3.5.0-amd64
  • PyCharm软件版本:pycharm-professional-2016.1.4
  • 电脑系统:Windows 10 64位

如果你还没有搭建好开发环境,请到这篇博客。


  • 本篇博客源代码GitHub里:这里。

这一篇博客的目的是爬取 169美女图片网 里面的所有的“西洋美女”的高清图片。

Alt text


爬虫程序设计思路:

1 . 先得到 http://www.169bb.com/xiyangmeinv/ 页面里面所有的照片后面对应的URL网页链接(如)。

2 . 接着在得到的URL链接网页里面得到里面所有高清图片的下载地址,进行下载。

3 . 得到所有 “西洋美女” 网页的页数。

Alt text


观察网页 和 网页源代码

1 . 打开 169美女图片网:http://www.169bb.com/

2 . 我们的目的是爬取这个站点里面所有 “西洋美女” 的高清图片。所以点击进入“西洋美女” 标签里。(http://www.169bb.com/xiyangmeinv/)

Alt text

3 . 观察这个页面,在页面最下面,显示了,当前一共311页。

Alt text

4 . 我们再来观察每页的网址有什么共同点,我们发现:第2页的网站是:http://www.169bb.com/xiyangmeinv/list_4_2.html;第3页的网址是:http://www.169bb.com/xiyangmeinv/list_4_3.html;而第1页的网站是:http://www.169bb.com/xiyangmeinv/list_4_1.html

这样每页的网址是有规律的,按照这个规律,我们可以推测出“西洋美女” 的第120页的网址就应该是:http://www.169bb.com/xiyangmeinv/list_4_120.html。事实的确是这样的。好。

5 . 现在,我们随便点击一个图片,进去看看这个美女的高清图片集。

里面都是高清的图片,并且有很多,并且,不止一页。就我随机点击的这个美女的链接就有11页,并且一页里面有5张左右的高清图片。

Alt text

6 . 并且它的每页的网址也是有规律的。

第2页是:http://www.169bb.com/xiyangmeinv/2016/1117/37333_2.html
第3页是:http://www.169bb.com/xiyangmeinv/2016/1117/37333_3.html
第1页是:http://www.169bb.com/xiyangmeinv/2016/1117/37333.html

但是有的美女的网址里只有一页,比如这个:http://www.169bb.com/xiyangmeinv/2016/0103/5974.html


好了,现在这个目标网页,我们已经分析完了。现在就可以编程。


写程序

源代码GitHub里:这里。

接下来我们为大家讲解大型图片爬虫项目编写实战。

Step 1 .

创建一个Scrapy爬虫项目:

scrapy startproject secondDemo

Alt text

创建一个scrapy爬虫文件,我们就在这个文件里面写爬取目标网站里面图片的爬虫程序。

cd secondDemo
scrapy genspider -t basic pic_169bb 169bb.com

Alt text


PyCharm 软件打开刚刚创建的 secondDemo 工程。

Alt text

Step 2 . items.py 文件里面的SeconddemoItem()函数里面创建一个对象,这个对象在其他的文件里面会使用到。

Alt text

Step 3 . 现在开始爬虫的编写。进入pic_169bb.py文件。

爬虫(pic_169bb.py文件)会自动的先爬首页(http://169bb.com/),爬完首页之后,会自动的进入parse()回调函数。

这个回调函数中,我们需要写些东西。

先获取所有栏目的名字和地址。

Alt text

查看源代码:

Alt text

pic_169bb.py 文件中的 parse()回调函数中添加下面的代码:

        urldata = response.xpath("/html/body/div[@class='header']/div[@class='hd_nav']/div[@class='w1000']//a/@href").extract()print(urldata)

Alt text

现在运行一下,输出:

Alt text


继续进行下一次的爬取:

先导入一个模块

from scrapy.http import Request

爬取子栏目的第一页,即西洋美女网址的第一页。

        xiyangurldata = urldata[4]  # 获取西洋美女首页网址print(xiyangurldata)yield Request(url=xiyangurldata, callback=self.next)def next(self, response):pass

Alt text

    def next(self, response):page_title_list = response.xpath("/html/body//div[@class='w1000 box03']/ul[@class='product01']//li/a/@alt").extract()print(page_title_list)page_url_list = response.xpath("/html/body//div[@class='w1000 box03']/ul[@class='product01']//li/a/@href").extract()print(page_url_list)pass

Alt text

运行输出一下:

Alt text


Alt text

        page_num = response.xpath("//span[@class='pageinfo']//strong/text()").extract()[0] # 得到西洋美女总页数print(page_num)print(response.url)for i in range(1, int(page_num)+1):page_url = response.url + 'list_4_'+ str(i) + '.html' # 得到西洋美女每一个页面的网址print(page_url)pass

Alt text

运行输出一下:

Alt text

Alt text


继续下一次:

        for i in range(1, int(page_num)+1):page_url = response.url + 'list_4_'+ str(i) + '.html' # 得到西洋美女每一个页面的网址print(page_url)yield Request(url=page_url, callback=self.next2)passdef next2(self, response):pass

Alt text


现在获取每一个美女的网页网址:

    def next2(self, response):page_title_list = response.xpath("/html/body//div[@class='w1000 box03']/ul[@class='product01']//li/a/@alt").extract()# print(page_title_list)page_url_list = response.xpath("/html/body//div[@class='w1000 box03']/ul[@class='product01']//li/a/@href").extract()# print(page_url_list)for i in range(0, len(page_url_list)):gril_page_url = page_url_list[i]print(gril_page_url)yield Request(url=gril_page_url, callback=self.next3)passdef next3(self, response):pass

Alt text

运行程序看看:

Alt text


next3() 这个回调函数的功能就是得到一个美女网页里面的所有的页面的网址。

有的美女的网页里面只有一个页面,有的美女的网页里面有多个页面:

Alt text

Alt text

可以统一解决。


测试:

Alt text

Alt text

Alt text

输出:

Alt text


Alt text

Alt text

同样的回调函数

输出:

Alt text


所以,我们可以这样写程序:

当得到的页码为-3,说明这个美女的网页是单页的;如果得到的页码数不等于-3,说明这个美女的网页是多也的。

测试程序:

对于多页面的美女网页网址

Alt text

Alt text

运行输出:

D:\WorkSpace\python_ws\python-large-web-crawler\secondDemo>scrapy crawl pic_169bb --nolog
10
http://www.169bb.com/xiyangmeinv/2016/0717/36463.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_5.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_10.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_9.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_6.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_8.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_7.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_3.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_4.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_2.htmlD:\WorkSpace\python_ws\python-large-web-crawler\secondDemo>

对于单页面的美女网页:

    def parse(self, response):...yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0103/2268.html', callback=self.demo)

回调函输一样。

运行输出:

D:\WorkSpace\python_ws\python-large-web-crawler\secondDemo>scrapy crawl pic_169bb --nolog
-3
http://www.169bb.com/xiyangmeinv/2016/0103/2268.htmlD:\WorkSpace\python_ws\python-large-web-crawler\secondDemo>

成功。

所以现在的爬虫代码应该是这样的:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import Requestclass Pic169bbSpider(scrapy.Spider):name = "pic_169bb"allowed_domains = ["169bb.com"]start_urls = ['http://169bb.com/']def parse(self, response):title_list = response.xpath("/html/body/div[@class='header']/div[@class='hd_nav']/div[@class='w1000']//a/text()").extract()# print(title_list)urldata = response.xpath("/html/body/div[@class='header']/div[@class='hd_nav']/div[@class='w1000']//a/@href").extract()#print(urldata)xiyang_title = title_list[4] # 获取西洋美女标签的文本内容xiyang_urldata = urldata[4]  # 获取西洋美女首页网址# print(xiyang_title, xiyang_urldata)yield Request(url=xiyang_urldata, callback=self.next)# yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0717/36463.html', callback=self.demo)# yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0103/2268.html', callback=self.demo)def next(self, response):page_num_str = response.xpath("//span[@class='pageinfo']//strong/text()").extract()[0] # 得到西洋美女总页数# print(page_num_str)# print(response.url)for i in range(1, int(page_num_str)+1):page_url = response.url + 'list_4_'+ str(i) + '.html' # 得到西洋美女每一个页面的网址# print(page_url)yield Request(url=page_url, callback=self.next2)passdef next2(self, response):page_title_list = response.xpath("/html/body//div[@class='w1000 box03']/ul[@class='product01']//li/a/@alt").extract()# print(page_title_list)page_url_list = response.xpath("/html/body//div[@class='w1000 box03']/ul[@class='product01']//li/a/@href").extract()# print(page_url_list)for i in range(0, len(page_url_list)):gril_page_url = page_url_list[i] # 得到西洋美女页面里面每一个美女的网页网址print(gril_page_url)yield Request(url=gril_page_url, callback=self.next3)passdef next3(self, response):rela_pages_list = response.xpath("//div[@class='dede_pages']/ul//li/a/text()").extract()pages_num = len(rela_pages_list) - 3# print(pages_num)self.getPic(response)if pages_num == -3:# pages_num = 1returnfor i in range(2, pages_num+1):girl_page_url = response.url.replace('.html', '_') + str(i) + '.html'# print(girl_page_url)yield Request(url=girl_page_url, callback=self.next4)pass# def demo(self, response):# #     rela_pages_list = response.xpath("//div[@class='dede_pages']/ul//li/a/text()").extract()# #     pages_num = len(rela_pages_list)-3# #     print(pages_num)# #     pass#     rela_pages_list = response.xpath("//div[@class='dede_pages']/ul//li/a/text()").extract()#     pages_num = len(rela_pages_list) - 3#     # print(pages_num)#     self.getPic(response)#     if pages_num == -3:#         # pages_num = 1#         return#     for i in range(2, pages_num+1):#         girl_page_url = response.url.replace('.html', '_') + str(i) + '.html'#         # print(girl_page_url)#         yield Request(url=girl_page_url, callback=self.next4)#     passdef next4(self, response):self.getPic(response)passdef getPic(self, response):print(response.url)pass

现在,我们需要在getPic() 函数中获取每一个美女网页的每一个页面里面的所有高清图片。

Alt text

    def getPic(self, response):# print(response.url)item = SeconddemoItem()item['url'] = response.xpath("//div[@class='big-pic']/div[@class='big_img']//p/img/@src").extract()print(item['url'])pass

测试运行:

测试多页的美女网页:

先将parse()函数的最后一行改为:yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0717/36463.html', callback=self.demo)

Alt text

测试单页的美女网页:

parse()函数的最后一行改为:yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0103/2268.html', callback=self.demo)

Alt text

成功。


下载高清图片

OK,现在我们就已经得到了所有西洋美女的所有高清图片的下载地址,我们在piplines.py 文件中使用它们。

删除了next4()回调函数。在demo()回调函数里面调用的都是getPic()回调函数。

    def demo(self, response):#     rela_pages_list = response.xpath("//div[@class='dede_pages']/ul//li/a/text()").extract()#     pages_num = len(rela_pages_list)-3#     print(pages_num)#     passrela_pages_list = response.xpath("//div[@class='dede_pages']/ul//li/a/text()").extract()pages_num = len(rela_pages_list) - 3# print(pages_num)self.getPic(response)if pages_num == -3:# pages_num = 1returnfor i in range(2, pages_num+1):girl_page_url = response.url.replace('.html', '_') + str(i) + '.html'# print(girl_page_url)yield Request(url=girl_page_url, callback=self.getPic)pass# error : yield 经过了一个中间函数,运行就有问题。我现在还不知道为什么# def next4(self, response):#     self.getPic(response)#     pass

并将getPic()函数里面的item写到生成器里面:

    def getPic(self, response):# print(response.url)item = SeconddemoItem()item['url'] = response.xpath("//div[@class='big-pic']/div[@class='big_img']//p/img/@src").extract()# print(item['url'])# passyield item

测试:

测试单页的美女网页:

parse()函数的最后一行改为:yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0103/2268.html', callback=self.getPic)

成功。

测试多页的美女网页:

先将parse()函数的最后一行改为:yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0717/36463.html', callback=self.demo)

Alt text

也算算成功,因为有重复的文件名,所以自动替换,所以这里需要做修改。

我们可以使用美女图片网址里面的数字作为图片文件名的固定前缀来给图片命名,使用正则表达式获取网址的数字。


pipelines.py 文件 中的 process_item() 函数中使用正则表达式得到图片下载网址的数字:

import re
import urllib.requestclass SeconddemoPipeline(object):def process_item(self, item, spider):# print(len(item['url']))for i in range(0, len(item['url'])):this_url = item['url'][i]id = re.findall('http://724.169pp.net/169mm/(.*?).jpg', this_url)[0]id = id.replace('/', '_')print(id)# file = 'D:/WorkSpace/python_ws/python-large-web-crawler/xiyangmeinv/' + str(i) + '.jpg'# print('Downloading :' , file)# urllib.request.urlretrieve(this_url, filename=file)# print('Final Download :' , file)return item

Alt text

要想使用 pipelines.py 文件 中的 SeconddemoPipeline 类,需要在 settings.py 文件里面设置 ITEM_PIPELINES 项:

ITEM_PIPELINES = {'secondDemo.pipelines.SeconddemoPipeline': 300,
}

Alt text

这里,我有一件事情不懂,关于正则表达式的: 网址里面的. 也是正则表达式中的工具字符,也是数据中中的内容,那么正则表达式是如何分辨它在这里是功能字符还是内容字符?

pic_169bb.py 文件的demo() 回调函数中,这样写才能获取到美女网页的第一页的图片地址:

        # error# self.getPic(response)# succes 为啥将下面的代码用self.getPic(response)的形式不能正常的获取到,而使用下面的代码却能获取到?item = SeconddemoItem()item['url'] = response.xpath("//div[@class='big-pic']/div[@class='big_img']//p/img/@src").extract()# print(item['url'])# passyield item

Alt text

运行程序试试:

测试单页的美女网页:

parse()函数的最后一行改为:yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0103/2268.html', callback=self.getPic)

Alt text

成功。

测试多页的美女网页:

先将parse()函数的最后一行改为:yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0717/36463.html', callback=self.demo)

Alt text

都成功。


先测试下载图片:

pipelines.py 文件 中的 SeconddemoPipeline 类的process_item() 函数里面,添加代码:

    def process_item(self, item, spider):# print(len(item['url']))for i in range(0, len(item['url'])):this_url = item['url'][i]id = re.findall('http://724.169pp.net/169mm/(.*?).jpg', this_url)[0]id = id.replace('/', '_')# print(id)file = 'D:/WorkSpace/python_ws/python-large-web-crawler/xiyangmeinv/' + id + '.jpg'print('Downloading :' , file)urllib.request.urlretrieve(this_url, filename=file)print('Final Download :' , file)return item

Alt text

运行程序,没有毛病:(除了下载速度有点慢)

Alt text


下载 169美女图片网 的所有西洋美女的图片

pic_169bb.py文件里, 将parse()函数的最后一行改为:yield Request(url=xiyang_urldata, callback=self.next)

Alt text

demo() 函数里面的所有代码复制一份到 next3()函数里:

Alt text

现在,运行程序:(最终的程序)

Alt text

Alt text

成功!


防反爬技术

Step 4 . 不遵循 robots.txt 协议。

settings.py 文件里面的 ROBOTSTXT_OBEY 项设置为:False

Alt text


Step 6 . 模仿浏览器

请先查看这篇博客:http://blog.csdn.net/github_35160620/article/details/52489709 里面是:六 . 设置 用户代理(user_agent)

settings.py 文件里面的 USER_AGENT 项设置为:浏览器的用户代理信息。

USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.22 Safari/537.36 SE 2.X MetaSr 1.0'

Step 7 . 禁止缓存

settings.py 文件里面的 COOKIES_ENABLED 项设置为:False

COOKIES_ENABLED = False

搞定


需要升级的地方:(2016-11-27 19:34:34)

  1. 在易错的代码段加上异常检测程序
  2. 在下载图片的代码加上:超时异常检测程序
  3. 记录成功下载的、超时失败下载的、链接失败下载的 信息
  4. 添加断点续下功能。

请访问:http://www.aobosir.com/


http://www.ppmy.cn/news/687768.html

相关文章

爬取福利,搞了一堆美女图片,代码奉上,多张福利

点赞再看,养成习惯 目录 展示成果: 分析网站 总结下: 技术分析 注:图片下载可运行

ModaHub ——向量数据库Milvus特征向量和预写式日志教程

目录 特征向量 什么是特征向量 特征向量的优势 应用领域 预写式日志 数据可靠性 缓冲区设置 旧日志删除 特征向量 什么是特征向量 向量是具有一定大小和方向的量,可以简单理解为一串数字的集合,就像一行多列的矩阵,比如&#xff1a…

【骚操作】Python 教你无损提取视频中的美女图片

前言 人类都是视觉动物,不管是男生还是女生看到漂亮的小姐姐、小哥哥就想截图保存下来。可是截图会对画质会产生损耗,截取的 画面不规整,像素不高等问题。 用 Python 写一个逐帧无损保存视频画面的小脚本大致可以分为三个步骤: …

花瓣网爬取美女图片 每次20张

现在是晚上11点40了,今天是第一天学习爬虫知识,初学者,只是很大概的接触Python的语法,所以今天一下午加晚上学的挺累的。 遇到第一个问题就是Python脚本运行出现语法错误:IndentationError: unindent does not match …

用python爬虫爬取海量高清美女图片,亲测2021年12月20日可用,适合初学者

因为近期在自学python,想着先通过一些项目提升对这个编程语言的兴趣,而且爬虫也是python中对基本功要求较低的项目,就根据所学内容编写了一个爬虫项目爬取某网站的图片。温馨提示:爬虫学得好,牢饭吃到饱,学…

Java爬虫-使用爬虫下载千张美女图片!

目的 爬取搜狗图片上千张美女图片并下载到本地 准备工作 爬取地址:https://pic.sogou.com/pics?query%E7%BE%8E%E5%A5%B3 分析 打开上面的地址,按F12开发者工具 - NetWork - XHR - 页面往下滑动XHR栏出现请求信息如下: Request URL &a…

手把手带你爬取百度美女图片,Python练手项目!

本文纯技术角度出发,教你如何用Python爬虫获取百度美女图片——技术无罪。 目标站点 百度图片使用关键字搜索 小姐姐私房照 https://image.baidu.com/开发环境 系统:Windows10 64位Python版本:Python3.6.5(Python3以上版本即可)IDE&#…

vuex-persistedstate —— 数据持久化

在之前的篇目当中对于 Vuex 中的相关内容都讲得差不多,但是在项目中去使用vuex,虽然数据状态得到管理了,但数据在每一次都需要去重新加载,那么对于数据的持久化vue是没有给解决的,而是通过第三方的工具去进行数据的持久…