图片爬虫

之前的例子里我们开发的都是文本爬虫,有时候我们需要去下载其他网站的图片并保存下来,这时候就需要用图片爬虫。

图片爬虫的套路其实跟文本爬虫差不多,最大的区别就是图片爬虫会去下载需要的文件,而文本爬虫可能会做其他的一些持久化的工作。

在这一节里,我们将实现下载煎蛋画廊第一页所有图片的功能。

具体步骤

  • 访问煎蛋画廊主页,获取html文本
  • 分析html文本,找出所有图片的html特征
  • 解析html代码,拿到所有图片的src
  • 通过src去下载图片

分析html代码

图片的html标签是img,所以我们只需要拿到页面上所有的img标签的src就好了。

下载文件

通过下面的代码,我们可以使用requests库来下载文件。

def download_file(url):
    print('Downding %s' %url)
    local_filename = url.split('/')[-1]
    r = requests.get(url, stream=True)
    with open(local_filename, 'wb') as f:
        for chunk in r.iter_content(chunk_size=1024):
            if chunk:
                f.write(chunk)
                f.flush()
    return local_filename

download_file方法只需要传入具体文件的地址就可以完成下载文件的功能了。

user agent

由于煎蛋做了非常简单的反爬虫处理,该站点会拒绝所有看起来像是爬虫的请求,大概的逻辑可能是如果后台发现请求的user agent异常,就返回403错误。

这里是User-Agent的基础知识,大家可以自行学习。

我们可以通过requests非常方便的修改请求的user agent,从而让被访问站点的后台没有办法识别出这次请求是否异常,达到绕过反爬机制的目的。

headers = {
    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
}

requests.get(url, headers=headers).text

上面代码的核心思想就是通过修改http headers中user agent,达到将请求伪装成是来自普通chrome浏览器访问的目的。

代码

新建名为get_images.py的文件,输入下面的内容


import requests
from bs4 import BeautifulSoup

headers = {
    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
}

def download_file(url):
    print('Downding %s' %url)
    local_filename = url.split('/')[-1]
    r = requests.get(url, stream=True, headers=headers)
    with open(local_filename, 'wb') as f:
        for chunk in r.iter_content(chunk_size=1024):
            if chunk:
                f.write(chunk)
                f.flush()
    return local_filename

url = 'http://jandan.net/drawings'
soup = BeautifulSoup(requests.get(url, headers=headers).text, 'html.parser')

def valid_img(src):
    return src.endswith('jpg') and 'img.jandan.net' in src

for img in soup.find_all('img', src=valid_img):
    src = img['src']
    if not src.startswith('http'):
        src = 'http:' + src
    download_file(src)

运行

在命令行中输入

python get_images.py

预期结果

如果一切正常,那么应该可以看到类似下面的结果,注意,因为数据是动态的,所有结果可能不会完全一致

Downding http://img.jandan.net/news/2017/12/2421ac6d8f4f6e5f680e8500371da976.jpg
Downding http://img.jandan.net/news/2017/11/07bad514db7d14532548e8e295b52613.jpg
Downding http://img.jandan.net/news/2017/11/a6eef4338379d0d41636b5597437802a.jpg
Downding http://img.jandan.net/news/2017/11/a7e3a32498ebc0c7849dc385dd83fb7b.jpg
Downding http://img.jandan.net/news/2017/11/cf600bb083f864b8087d3c4197a82e68.jpg
Downding http://img.jandan.net/news/2017/11/e452965157a114f96811201ba7a2b04a.jpg
Downding http://img.jandan.net/news/2017/11/b9e218f234026ee89e06b02fe97491ba.jpg
Downding http://img.jandan.net/news/2017/11/cdb8b79717721a574c2e48d655faf322.jpg
Downding http://img.jandan.net/news/2017/11/3fafb25784f8b8af520a2a5363e6d2a8.jpg
Downding http://img.jandan.net/news/2017/11/b07c5ae27a15d77115aa123a762fa16f.jpg
Downding http://img.jandan.net/news/2017/11/fed4d3ed5a91d60fffb1160da40e93e0.jpg
Downding http://img.jandan.net/news/2017/11/3de5872698ffec208961f48bfd9c9081.jpg
Downding http://img.jandan.net/news/2017/11/80d507ebe1ffec11264729b4e6550880.jpg
Downding http://img.jandan.net/news/2017/11/5c550fb5d706c99343b3027bdb5f182e.jpg
Downding http://img.jandan.net/news/2017/11/f647536a58e710fb0ae9bdacad7728bb.jpg
Downding http://img.jandan.net/news/2017/11/ae6773d7f9e717ce7ecb737612fdbfc9.jpg
Downding http://img.jandan.net/news/2017/11/071af60d6a3a0207533fe0ef96e9cec7.jpg
Downding http://img.jandan.net/news/2017/11/da7537e046123818a79984ac8ff8c719.jpg
Downding http://img.jandan.net/news/2017/11/f84a7fc386de355964d8134da99917e4.jpg
Downding http://img.jandan.net/news/2017/11/518bf5d720dc4ff59e1e4a2f06da7bc9.jpg
Downding http://img.jandan.net/news/2017/11/a11c97c08d45db8f02ee8872c36bc947.jpg
Downding http://img.jandan.net/news/2017/10/0a0dc6ccffbb03e6f02212ed5e84d82c.jpg
Downding http://img.jandan.net/news/2017/10/48e3f9dae268748aa80f55f924505b95.jpg
Downding http://img.jandan.net/news/2017/07/8aabbd1577eac72856768e49482f9a97.jpg
Downding http://img.jandan.net/news/2017/10/0e7b6f9a95e63522341d1a2938ac0768.jpg
Downding http://img.jandan.net/news/2017/10/345b4bcbe916744c723665a3bfd8c2fb.jpg
Downding http://img.jandan.net/news/2017/10/b9a8a71a00f68b1f50ebd37f1f66f98c.jpg
Downding http://img.jandan.net/news/2017/07/877e4a9e59aae3b803b8a1b85913a439.jpg
Downding http://img.jandan.net/news/2017/10/61f5d62654a90e92ad990964b54b7e73.jpg
Downding http://img.jandan.net/news/2017/09/65d88cd53b2dd4dcce78634f8f45d0db.jpg

当前文件夹下应该会保存有这些图片。

我们可以学到什么

这一节里我们使用到了bs的过滤器功能。

def valid_img(src):
    return src.endswith('jpg') and 'img.jandan.net' in src

soup.find_all('img', src=valid_img):

上面代码实现了只查找src文件名以jpg结尾的,并且src中包含img.jandan.net的img标签。

阅读内容

BeautifulSoup