[关闭]
@wade123 2019-03-26T08:51:58.000000Z 字数 5549 阅读 1238

实战项目 3:单页图片爬取:,以网易数独信息图为例

Python入门爬虫与数据分析


上一个爬虫实战,我们爬取了网页中的文本信息,这一讲介绍如何爬取网页中的图片。先尝试爬一张图片,然后爬一页图片,最后爬取多页图片,循环渐进、从易到难。

1. 目标网站

这是我们要爬取的网站:

2. 单张图片下载

随意打开一篇文章,挑选一张图片,使用 Requests ,5 行代码就把它下载下来。

  1. import requests
  2. url = 'http://cms-bucket.nosdn.127.net/2018/08/31/df39aac05e0b417a80487562cdf6ca40.png'
  3. response = requests.get(url)
  4. with open('北京房租地图.jpg', 'wb') as f:
  5. f.write(response.content)

这里获取图片,使用 response.content 返回图片二进制数据。若想了解,图片为什么可以用二进制数据进行存储,可以参考这个教程:
https://www.zhihu.com/question/36269548/answer/66734582

接下来,我们下载这篇文章中的所有图片,超过 15 张。

3. 单页图片下载

网址:http://data.163.com/18/0901/01/DQJ3D0D9000181IU.html

先获取这篇文章的网页源代码:

  1. import requests
  2. headers = {
  3. 'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
  4. }
  5. url = 'http://data.163.com/18/0901/01/DQJ3D0D9000181IU.html'
  6. response = requests.get(url,headers = headers)
  7. if response.status_code == 200:
  8. # return response.text
  9. print(response.text) # 测试网页内容是否提取成功 ok

接下来解析源代码,从中提取出所有图片 url。

之前在爬取猫眼票房分析的实战中,我们使用了多种方法提取网页信息。现在,再来练习一次,分别使用:正则表达式、Xpath、BeautifulSoup、CSS、PyQuery 提取。

在网页中定位到图片 url 所在位置: <p>节点--<a>节点--<img>节点里的 src 属性值

正则表达式提取

  1. import re
  2. pattern =re.compile('<p>.*?<img alt="房租".*?src="(.*?)".*?style',re.S)
  3. items = re.findall(pattern,html)
  4. # print(items)
  5. for item in items:
  6. yield{
  7. 'url':item
  8. }

输出提取结果如下:

  1. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/425eca61322a4f99837988bb78a001ac.png'}
  2. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/df39aac05e0b417a80487562cdf6ca40.png'}
  3. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/d6cb58a6bb014b8683b232f3c00f0e39.png'}
  4. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/88d2e535765a4ed09e03877238647aa5.png'}
  5. {'url': 'http://cms-bucket.nosdn.127.net/2018/09/01/98d2f9579e9e49aeb76ad6155e8fc4ea.png'}
  6. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/7410ed4041a94cab8f30e8de53aaaaa1.png'}
  7. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/49a0c80a140b4f1aa03724654c5a39af.png'}
  8. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/3070964278bf4637ba3d92b6bb771cea.png'}
  9. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/812b7a51475246a9b57f467940626c5c.png'}
  10. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/8bcbc7d180f74397addc74e47eaa1f63.png'}
  11. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/e593efca849744489096a77aafd10d3e.png'}
  12. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/7653feecbfd94758a8a0ff599915d435.png'}
  13. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/edbaa24a17dc4cca9430761bfc557ffb.png'}
  14. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/f768d440d9f14b8bb58e3c425345b97e.png'}
  15. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/3430043fd305411782f43d3d8635d632.png'}
  16. {'url': 'http://cms-bucket.nosdn.127.net/2018/08/31/111ba73d11084c68b8db85cdd6d474a7.png'}

XPath 语法提取

  1. from lxml import etree
  2. parse = etree.HTML(html)
  3. items = parse.xpath('*//p//img[@alt = "房租"]/@src')
  4. print(items)
  5. for item in items:
  6. yield{
  7. 'url':item
  8. }

结果同上。

CSS 选择器提取

  1. soup = BeautifulSoup(html,'lxml')
  2. items = soup.select('p > a > img') #>表示下级绝对节点
  3. # print(items)
  4. for item in items:
  5. yield{
  6. 'url':item['src']
  7. }

BeautifulSoup find_all 提取

  1. soup = BeautifulSoup(html,'lxml')
  2. # 每个网页只能拥有一个<H1>标签,因此唯一
  3. item = soup.find_all(name='img',width =['100%'])
  4. for i in range(len(item)):
  5. url = item[i].attrs['src']
  6. yield{
  7. 'url':url
  8. }

PyQuery 提取

  1. from pyquery import PyQuery as pq
  2. data = pq(html)
  3. data2 = data('p > a > img')
  4. # print(items)
  5. for item in data2.items(): #注意这里和 BeautifulSoup 的 css 用法不同
  6. yield{
  7. 'url':item.attr('src')
  8. # 或者'url':item.attr.src
  9. }

以上用 5 种方法提取出了网页 url 地址。任选一种即可,这里选择第 4 种方法提取内容,下面下载图片。

  1. title = pic.get('title')
  2. url = pic.get('pic')
  3. # 设置图片编号顺序
  4. num = pic.get('num')
  5. # 建立文件夹
  6. if not os.path.exists(title):
  7. os.mkdir(title)
  8. # 获取图片 url 网页信息
  9. response = requests.get(url,headers = headers)
  10. # 建立图片存放地址
  11. file_path = '{0}\{1}.{2}' .format(title,num,'jpg')
  12. # 文件名采用编号方便按顺序查看
  13. # 开始下载图片
  14. with open(file_path,'wb') as f:
  15. f.write(response.content)
  16. print('该图片已下载完成',title)

提取出的网址是字典结构,可用 get 方法调用键和值。建立图片存放文件夹和编号,运行程序,全文图片就下载下来了。

将上述代码再完善一下,增加异常处理、图片标题、编号,完整代码如下所示:

  1. import requests
  2. from bs4 import BeautifulSoup
  3. import re
  4. import os
  5. from hashlib import md5
  6. from requests.exceptions import RequestException
  7. from multiprocessing import Pool
  8. from urllib.parse import urlencode
  9. headers = {
  10. 'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
  11. }
  12. def get_page():
  13. # 下载 1 页
  14. url = 'http://data.163.com/18/0901/01/DQJ3D0D9000181IU.html'
  15. # 增加异常捕获语句
  16. try:
  17. response = requests.get(url,headers = headers)
  18. if response.status_code == 200:
  19. return response.text
  20. # print(response.text) # 测试网页内容是否提取成功
  21. except RequestException:
  22. print('网页请求失败')
  23. return None
  24. def parse_page(html):
  25. soup = BeautifulSoup(html,'lxml')
  26. # 获取 title
  27. title = soup.h1.string
  28. # 每个网页只能拥有一个<H1>标签,因此唯一
  29. item = soup.find_all(name='img',width =['100%'])
  30. # print(item) # 测试
  31. for i in range(len(item)):
  32. pic = item[i].attrs['src']
  33. yield{
  34. 'title':title,
  35. 'pic':pic,
  36. 'num':i # 图片添加编号顺序
  37. }
  38. def save_pic(pic):
  39. title = pic.get('title')
  40. url = pic.get('pic')
  41. # 设置图片编号顺序
  42. num = pic.get('num')
  43. if not os.path.exists(title):
  44. os.mkdir(title)
  45. # 获取图片 url 网页信息
  46. response = requests.get(url,headers = headers)
  47. try:
  48. # 建立图片存放地址
  49. if response.status_code == 200:
  50. file_path = '{0}\{1}.{2}' .format(title,num,'jpg')
  51. # 文件名采用编号方便按顺序查看,而未采用哈希值 md5(response.content).hexdigest()
  52. if not os.path.exists(file_path):
  53. # 开始下载图片
  54. with open(file_path,'wb') as f:
  55. f.write(response.content)
  56. print('该图片已下载完成',title)
  57. else:
  58. print('该图片%s 已下载' %title)
  59. except RequestException as e:
  60. print(e,'图片获取失败')
  61. return None
  62. def main():
  63. # get_page() # 测试网页内容是获取成功 ok
  64. html = get_page()
  65. # parse_page(html) # 测试网页内容是否解析成功 ok
  66. data = parse_page(html)
  67. for pic in data:
  68. # print(pic) #测试 dict
  69. save_pic(pic)
  70. # 单进程
  71. if __name__ == '__main__':
  72. main()

以上,我们使用爬虫先爬取了单张图片,接着爬取了一页图片。

完整代码和素材,可以在下方链接中得到:
https://github.com/makcyun/web_scraping_with_python/tree/master/python%E7%88%AC%E8%99%AB(3)%EF%BC%9A%E5%8D%95%E9%A1%B5%E5%9B%BE%E7%89%87%E4%B8%8B%E8%BD%BD-%E7%BD%91%E6%98%93%E6%95%B0%E8%AF%BB%E4%BF%A1%E6%81%AF%E5%9B%BE

下一篇文章练习爬取多页图片。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注