Python 3实战爬虫之爬取京东图书的图片详解


Posted in Python onOctober 09, 2017

前言

最近工作中遇到一个需求,需要将京东上图书的图片下载下来,假如我们想把京东商城图书类的图片类商品图片全部下载到本地,通过手工复制粘贴将是一项非常庞大的工程,此时,可以用Python网络爬虫实现,这类爬虫称为图片爬虫,接下来,我们将实现该爬虫。

实现分析

首先,打开要爬取的第一个网页,这个网页将作为要爬取的起始页面。我们打开京东,选择图书分类,由于图书所有种类的图书有很多,我们选择爬取所有编程语言的图书图片吧,网址为:https://list.jd.com/list.html?cat=1713,3287,3797&page=1&sort=sort_rank_asc&trans=1&JL=6_0_0#J_main

如图:

Python 3实战爬虫之爬取京东图书的图片详解

进去后,我们会发现总共有251页。

那么我们怎么才能自动爬取第一页以外的其他页面呢?

可以单击“下一页”,观察网址的变化。在单击了下一页之后,发现网址变成了https://list.jd.com/list.html?cat=1713,3287,3797&page=2&sort=sort_rank_asc&trans=1&JL=6_0_0#J_main。

我们可以发现,在这里要获取第几页是通过URL网址识别的,即通过GET方式请求的。在这个GET请求中,有多个字段,其中有一个字段为page,对应值为2,由此,我们可以得到该网址中的关键信息为:https://list.jd.com/list.html?cat=1713,3287,3797&page=2。接下来,我们根据推测,将page=2改成page=6,发现我们能够成功进入第6页。

由此,我们可以想到自动获取多个页面的方法:可以使用for循环实现,每次循环后,对应的网址中page字段加1,即自动切换到下一页。

在每页中,我们都要提取对应的图片,可以使用正则表达式匹配源码中图片的链接部分,然后通过urllib.request.urlretrieve()将对应链接的图片保存到本地。

但是这里有一个问题,该网页中的图片不仅包括列表中的商品图片,还包括旁边的一些无关图片,所以我们可以先进行一次信息过滤,第一次信息过滤将中间的商品列表部分数据留下,将其他部分的数据过滤掉。可以单击右键,然后查看网页的源代码,如图:

Python 3实战爬虫之爬取京东图书的图片详解

可以通过商品列表中的第一个商品名为“JAVA从入门到精通”快速定位到源码中的对应位置,然后观察其商品列表部分的特殊标识,可以看到,其上方有处“<div id="plist”代码,然后我们在源码中搜索该代码,发现只有一个地方有,随后打开其他页的对应页面,发现仍然具有这个规律,说明该特殊标识可以作为有效信息的起始过滤位置。当然,你可以使用其他的代码作为特殊标识,但是该特殊标识要满足唯一性,并且要包含要爬取的信息。

那么,有效信息到什么代码位置结束呢?

同样,我们通过在源码中查找该页商品列表中最后一个图书,快速定位到源码位置,进行分析,我们可以找到一个这样的代码作为标识,如图:

Python 3实战爬虫之爬取京东图书的图片详解

所以,如果要进行第一次过滤,我们的正则表达式可以构造为:

<div id="plist".+? <div class="page clearfix">

进行了第一次信息过滤后,留下来的图片链接就是我们想爬取的图片了,下一步需要在第一次过滤的基础上,再将图片链接信息过滤出来。

此时,需要观察网页中对应图片的源代码,我们观察到其中两张图片的对应源码:

图片1:

<img width="200" height="200" data-img="1" src="//img13.360buyimg.com/n7/jfs/t6130/167/771989293/235186/608d0264/592bf167Naf49f7f6.jpg">

图片2:

<img width="200" height="200" data-img="1" src="//img10.360buyimg.com/n7/g14/M03/0E/0D/rBEhV1Im1n8IAAAAAAcHltD_3_8AAC0FgC-1WoABweu831.jpg">

对比两张图片代码,发现其基本格式是一样的,只是图片的链接网址不一样,所以此时,我们根据该规律构造出提取图片链接的正则表达式:

<img width="200" height="200" data-img="1" src="//(.+?\.jpg)">

刚开始到这里,我以为就结束了,后来在爬取的过程中我发现每一页都少爬取了很多图片,再次查看源码发现,每页后面的几十张图片又是另一种格式:

<img width="200" height="200" data-img="1" data-lazy-img="//img10.360buyimg.com/n7/jfs/t3226/230/618950227/110172/7749a8bc/57bb23ebNfe011bfe.jpg">

所以,完整的正则表达式应该是这两种格式的或:

<img width="200" height="200" data-img="1" src="//(.+?\.jpg)">|<img width="200" height="200" data-img="1" data-lazy-img="//(.+?\.jpg)">

到这里,我们根据该正则表达式,就可以提取出一个页面中所有想要爬取的图片链接。

所以,根据上面的分析,我们可以得到该爬虫的编写思路与过程,具体如下:

  • 建立一个爬取图片的自定义函数,该函数负责爬取一个页面下的我们想爬取的图片,爬取过程为:首先通过urllib.request.utlopen(url).read()读取对应网页的全部源代码,然后根据上面的第一个正则表达式进行第一次信息过滤,过滤完成之后,在第一次过滤结果的基础上,根据上面的第二个正则表达式进行第二次信息过滤,提取出该网页上所有的目标图片的链接,并将这些链接地址存储的一个列表中,随后遍历该列表,分别将对应链接通过urllib.request.urlretrieve(imageurl,filename=imagename)存储到本地,为了避免程序中途异常崩溃,我们可以建立异常处理。
  • 通过for循环将该分类下的所有网页都爬取一遍,链接可以构造为url='https://list.jd.com/list.html?cat=1713,3287,3797&page=' + str(i)

完整的代码如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import re
import urllib.request
import urllib.error
import urllib.parse


sum = 0
def craw(url,page):
 html1=urllib.request.urlopen(url).read()
 html1=str(html1)
 pat1=r'<div id="plist".+? <div class="page clearfix">'
 result1=re.compile(pat1).findall(html1)
 result1=result1[0]
 pat2=r'<img width="200" height="200" data-img="1" src="//(.+?\.jpg)">|<img width="200" height="200" data-img="1" data-lazy-img="//(.+?\.jpg)">'
 imagelist=re.compile(pat2).findall(result1)
 x=1
 global sum
 for imageurl in imagelist:
  imagename='./books/'+str(page)+':'+str(x)+'.jpg'
  if imageurl[0]!='':
   imageurl='http://'+imageurl[0]
  else:
   imageurl='http://'+imageurl[1]
  print('开始爬取第%d页第%d张图片'%(page,x))

  try:
   urllib.request.urlretrieve(imageurl,filename=imagename)
  except urllib.error.URLError as e:
   if hasattr(e,'code') or hasattr(e,'reason'):
    x+=1

  print('成功保存第%d页第%d张图片'%(page,x))
  x+=1
  sum+=1

for i in range(1,251):
 url='https://list.jd.com/list.html?cat=1713,3287,3797&page='+str(i)
 craw(url,i)
print('爬取图片结束,成功保存%d张图'%sum)

运行结果如下:

Python 3实战爬虫之爬取京东图书的图片详解

Python 3实战爬虫之爬取京东图书的图片详解

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
关于Python中异常(Exception)的汇总
Jan 18 Python
Python实现的文本编辑器功能示例
Jun 30 Python
python实现简易通讯录修改版
Mar 13 Python
详解Python的hasattr() getattr() setattr() 函数使用方法
Jul 09 Python
python logging重复记录日志问题的解决方法
Jul 12 Python
在pycharm 中添加运行参数的操作方法
Jan 19 Python
python利用re,bs4,requests模块获取股票数据
Jul 29 Python
django 配置阿里云OSS存储media文件的例子
Aug 20 Python
Python使用matplotlib实现交换式图形显示功能示例
Sep 06 Python
python自动化unittest yaml使用过程解析
Feb 03 Python
python读取与处理netcdf数据方式
Feb 14 Python
Python如何在windows环境安装pip及rarfile
Jun 15 Python
Python3实战之爬虫抓取网易云音乐的热门评论
Oct 09 #Python
Python读取文件内容的三种常用方式及效率比较
Oct 07 #Python
Python引用传值概念与用法实例小结
Oct 07 #Python
Python中执行存储过程及获取存储过程返回值的方法
Oct 07 #Python
Python使用cx_Oracle调用Oracle存储过程的方法示例
Oct 07 #Python
深入理解Django中内置的用户认证
Oct 06 #Python
Python3学习笔记之列表方法示例详解
Oct 06 #Python
You might like
随机广告显示(PHP函数)
2006/10/09 PHP
php计算整个目录大小的方法
2015/06/19 PHP
Yii视图操作之自定义分页实现方法
2016/07/14 PHP
php基于SQLite实现的分页功能示例
2017/06/21 PHP
PHP7新特性
2021/03/09 PHP
Javascript继承机制的设计思想分享
2011/08/28 Javascript
js自动下载文件到本地的实现代码
2013/04/28 Javascript
基于jQuery实现的双11天猫拆红包抽奖效果
2015/12/01 Javascript
AngularJs动态加载模块和依赖注入详解
2016/01/11 Javascript
JS实现图片放大缩小的方法
2017/02/15 Javascript
JS库中的Particles.js在vue上的运用案例分析
2017/09/13 Javascript
删除table表格行的实例讲解
2017/09/21 Javascript
原生JS实现日历组件的示例代码
2017/09/22 Javascript
对Vue table 动态表格td可编辑的方法详解
2018/08/28 Javascript
使用jQuery mobile NuGet让你的网站在移动设备上同样精彩
2019/06/18 jQuery
javscript 数组扁平化的实现
2020/02/03 Javascript
JS实现canvas简单小画板功能
2020/06/23 Javascript
[04:19]DOTA2完美大师赛第四天精彩集锦
2017/11/26 DOTA
Python Socket使用实例
2017/12/18 Python
python实现简易内存监控
2018/06/21 Python
python 生成图形验证码的方法示例
2018/11/11 Python
python实现彩色图转换成灰度图
2019/01/15 Python
Python爬取数据保存为Json格式的代码示例
2019/04/09 Python
pygame实现俄罗斯方块游戏(AI篇1)
2019/10/29 Python
Python实现图片裁剪的两种方式(Pillow和OpenCV)
2019/10/30 Python
Django Model中字段(field)的各种选项说明
2020/05/19 Python
基于Python实现视频的人脸融合功能
2020/06/12 Python
学校节能减排倡议书
2014/05/16 职场文书
贷款担保申请书
2014/05/20 职场文书
保护水资源的标语
2014/06/17 职场文书
小学生勤俭节约演讲稿
2014/08/28 职场文书
2014乡镇党政班子四风问题思想汇报
2014/09/14 职场文书
肖申克的救赎观后感
2015/06/02 职场文书
2015年文秘个人工作总结
2015/10/14 职场文书
2016年先进班集体事迹材料
2016/02/26 职场文书
一文搞清楚MySQL count(*)、count(1)、count(col)区别
2022/03/03 MySQL