Python爬虫-图片篇(2)初窥门径

对爬虫常用库不熟悉的读者,可以按顺序一次学习:
Python爬虫-图片篇(1) 详细的分析了网站图片爬虫的简单框架,和一些封装函数。

文章目录

  • 1. 内容介绍
  • 2. 程序分析
    • 2.0 设置等待时间
    • 2.1 请求头设置
    • 其他
  • 3. 知识点总结

1. 内容介绍

频繁的获取网站信息,可能会触发网站的反爬虫机制。这时候,我们就需要一些方法,来避免这样的问题。这篇文章就是来介绍爬虫中伪装方法。

2. 程序分析

#!usr/bin/env python
#-*- coding:utf-8 -*-
"""
@author:CHERN
@file: spider_nvshens.py
@time: 2020/04/29
"""

'''网站爬虫'''
# 网站防止盗链技术还不知道怎么解决:测试download_image_in_page()函数下载盗的图片是防盗链图片

import requests
import os
from lxml import etree
import json
from tqdm import tqdm
import random
import time

domain = "https://www.nvshens.net"

def get_all_pages_url(url):
    ''' Fetches all pages's url of album.
    :argument
        url: album url. "https://www.nvshens.net/g/30125/" for example.
    :returns
        urls: list of all pages's url of album
    :raise
        null
    '''
    print("Getting all pages' urls of album...")
    urlset = set([])
    while True:
        urlsetlen = len(urlset)
        r = requests.get(url)
        page = etree.HTML(r.text)
        urls = page.xpath('//*[@id="pages"]/a/@href')
        urls = urls[0:-1]  # urls最后一项是当前页,包含在其中,所以删掉
        for u in urls:
            urlset.add(u)
        url = domain + urls[-1]
        if urlsetlen == len(urlset):
            print("There exists " + str(len(urlset)) + ' pages in this album.')
            return list(urlset)

# 下载给定页面中的所有图片(只是单个page),输入时一个URL,和指定路径
def download_image_in_page(url,path):
    # 首先获取到页面重所有图片的URL
    page_header = {
        "Referer":url,
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }
    r = requests.get(url, headers=page_header)
    time.sleep(2)
    page = etree.HTML(r.text)
    img_urls = page.xpath('//*[@id="hgallery"]/img/@src')
    entry_title = page.xpath('//*[@id="htilte"]/text()')

    for img_url in img_urls:
        # 如果不设置请求头,那么会让网站欺骗,下载的图片是防盗链图片,而不是我们想要的
        Headers = {
            "Referer":url,
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36",
            "Accept": "image/webp,image/apng,image/*,*/*;q=0.8",
            "Accept-Encoding": "gzip, deflate, br",
            "Accept-Language": "zh-CN,zh;q=0.9,und;q=0.8,en;q=0.7",
            "Connection": "keep-alive",
            "Host": "img.onvshen.com:85",
            "Sec-Fetch-Dest": "image",
            "Sec-Fetch-Mode": "no-cors",
            "Sec-Fetch-Site": "cross-site"
        }
        dir = path + str(entry_title[-1])
        # 判断需要下载的图片是否存在,如果存在就进入下一张图片url
        if os.path.exists(dir + '/' + img_url.split('/')[-1]):
            continue
        if not os.path.exists(dir):
            os.makedirs(dir)
        img = requests.get(img_url, headers=Headers).content
        time.sleep(2)
        with open(dir + '/' + img_url.split('/')[-1], 'wb+') as f:
            f.write(img)
    return dir + '/'

# 给出一个相册集的URL,下载该URL对应作品集album中所有图片 https://www.nvshens.net/g/32596/
# 传入的url需要是绝对路径
def download_all_image_by_album(url,path):
    print("Downloading album.. URL: " + url)
    urls = get_all_pages_url(url)
    pbar = tqdm(urls)
    for url in pbar:
        pbar.set_description("Processing %s" % url)
        result = download_image_in_page(domain+url, path)
    print("Download album successfully. Go to folder:"+ result)
    print("="*30)
    return result

# 给出一个人的主页面https://www.nvshens.net/girl/27758/,下载它的所有作品,即所有albums中的所有图片,每个albums一个文件夹
# 主页的照片集在https://www.nvshens.net/girl/27758/album/中
# 如果超过30个album,会出现下一页的情况,下载还没解决。不过应该容易。直接获取下一页页面,解析出album,如果为空,就退出循环
def download_all_image_by_mainpage(url,path):
    # 先从主页中,获取一些个人资料
    # 可以在此处解析其他信息,如本站排名,体重,出生日期,星座等
    r = requests.get(url)
    r.encoding = r.apparent_encoding    # 可以用来防止乱码问题,如果出现乱码,应该首先考虑到是否是编码的问题
    page = etree.HTML(r.text)
    infocontent = page.xpath('//*[@id="post"]/div[5]/div/div[1]/div[2]/p/text()')
    print("Basic Info:"+infocontent[0])
    # 从相册目录获取所有相册,有可能是多页,所以循环读取,将解析到的相册集append到变量albums中
    # 如果albums在循环中长度没变,说明该页不存在相册集了
    # 可以解决一些人,作品集有很多页问题
    print("Gathering albums urls... ")
    al_page = 1
    album_set = set([])
    while True:
        # 记录当前已经收集到的相册集长度
        albums_len = len(album_set)
        # 开始搜索该页的相册集
        page = etree.HTML(requests.get(url+"/album/"+str(al_page)+".html").text)
        als = page.xpath('//*[@id="photo_list"]/ul/li/div[1]/a/@href')
        for al in als:
            album_set.add(al)
        # 对比搜索前后相册集长度,如果相等,就说明已经到最后一页了,就退出循环,否则al_page+1,进入下一页解析
        if albums_len == len(album_set):
            break
        al_page = al_page + 1
    albums = list(album_set)
    # 存在一些人相册集很少,在主页中就把所有相册集全部显示出来了,并没有/album/目录,下面是针对没有相册集的情况,直接从主页中获取相册集
    # 有一些作品比较少的人,是没有/album/目录的,直接在url中获取album
    # 例如,如果 url= https://www.nvshens.net/girl/25959/, 那么,就直接读取url就可以了
    if len(albums) == 0:
        r = requests.get(url)
        r.encoding = r.apparent_encoding  # 可以用来防止乱码问题,如果出现乱码,应该首先考虑到是否是编码的问题
        page = etree.HTML(r.text)
        albums = page.xpath('//*[@id="post"]/div[8]/div/div[3]/ul/li/div[1]/a/@href')
    print("There exists "+str(len(albums))+" albums in this main page.")
    print("Downloading them now..")
    print("="*30)
    te = 1
    for album in albums:
        print("Album " + str(te) + " is beening downloaded..")
        te = te + 1
        url = domain + album
        result = download_all_image_by_album(url,path)

# 板块:<美人榜>
# https://www.nvshens.net/tag/
# 注意返回的是相对路径如
# /girl/27772/
# /girl/27771/
# /girl/27770/
# /girl/27769/
# 这个标签可以通过requests获取解析得到,这里直接硬编码得到
tagdic={"演员":"yanyuan", "歌手":"geshou","模特&麻豆":"mote","车模&赛车女郎":"chemo","配音&声优":"peiyin",
        "主播&主持人":"zhubo","Cosplayer":"cosplayer","校花":"xiaohua","空姐":"kongjie","足球宝贝":"zuqiu",
        "Showgirl":"showgirl", "选美小姐":"xuanmei","书法美女":"shufa", "美女作家":"zuojia", "网络美女":"wangluo",
        "教师":"jiaoshi", "OL":"ol", "学生":"xuesheng", "写真女优":"xiezhen", "淘女郎":"tao", "体坛美女":"titan",
        "舞蹈家":"wudao","啦啦队":"laladui","企业家":"qiyejia","嫩模":"nenmo","瑜伽教练":"yujia",

        "内地女神":"neidi", }
def get_beautyli_300(tag):
    mainpage_urls = []
    for i in range(1,16):
        page = etree.HTML(requests.get(domain+"/tag/"+tag+"/"+str(i)+".html").text)
        mainpage_url = page.xpath('//*[@id="listdiv"]/ul/li/div/a/@href')
        mainpage_urls = mainpage_urls+mainpage_url
    return mainpage_urls

# 板块:<美女图片>
def get_all_alboms():
    pass

if __name__ == '__main__':
    # download_image_in_page("https://www.nvshens.net/g/32596/2.html","F:/imagedownload/nvshens/")

    # download_all_image_by_album("https://www.nvshens.net/g/32596/","F:/imagedownload/nvshens/")

    # 根据个人主页,下载属于她的所有相册
    # 乔依琳 https://www.nvshens.net/girl/25762/
    # 夏诗诗 https://www.nvshens.net/girl/27761
    # 小热巴 https://www.nvshens.net/girl/22204
    download_all_image_by_mainpage("https://www.nvshens.net/girl/27761/", "F:/imagedownload/nvshens/")

    # 下载内地榜前300人所有图片
    # mainpages = get_beautyli_300(tag=tagdic["瑜伽教练"])
    # for mainpage in mainpages:
        # download_all_image_by_mainpage(domain+mainpage,"F:/imagedownload/nvshens/")
        # print(mainpage)

2.0 设置等待时间

在某些网站中,有些时候并不需要复杂的反爬虫技术,而是只需要每次requests.get()访问他们的网站时,不要太频繁就可以了。因此使用time.sleep()函数有时候很管用。等待时间根据实际效果定。

2.1 请求头设置

请求头是为了把我们的请求,伪装成浏览器的一个手段。

其他

3. 知识点总结

  • requests.get()方法有一个headers参数,用来设置请求头。
  • 在循环获取网页信息的时候,我们有时候需要使用time.sleep()方法等待

更多详细的内容,以后逐渐补充

你可能感兴趣的:(爬虫)