zoukankan      html  css  js  c++  java
  • 爬取妹子图(requests + BeautifulSoup)

      刚刚入门爬虫,今天先对于单个图集进行爬取,过几天再进行翻页爬取。

      使用requests库和BeautifulSoup库

      目标网站:妹子图

    今天是对于单个图集的爬取,就选择一个进行爬取,我选择的链接为:http://www.mzitu.com/123114

    首先网站的分析,该网站有一定的反爬虫策略,所以应对就是加入headers(目前是小白,目前不知道具体为毛这样做)

    Hostreferer = {
        'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
        'Referer':'http://www.mzitu.com'
    }
    Picreferer = {
        'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
        'Referer':'http://i.meizitu.net'
    }

    前一个头作为请求网站,后一个头作为破解盗链使用

    获得页面HTML代码

    用requests库的get方法,加上Hostreferer

    def get_html(url):#获得页面html代码
        req = requests.get(url, headers=Hostreferer)
        html = req.text
        return html

    获得图集名称以及图集最大页数

    分析网页构成如图所示,图集名称包含在h2标签内,且该标签在整个HTML代码里有唯一的class="main-title",

    而最大页数只是被span标签包含,无法通过属性来提取。所以提取图集名称采取标签名+属性名一起提取,而最大页数就采取将span标签全部找出,最大页数在span标签中第11位,

     

    def get_page_name(url):#获得图集最大页数和名称
        html = get_html(url)
        soup = BeautifulSoup(html, 'lxml')
        span = soup.findAll('span')
        title = soup.find('h2', class_="main-title")
        return span[10].text, title.text

    获得图片url链接

      分析页面内容,含有图片链接的img标签中有一个alt属性的值是跟图集名称相同,可以用这个来直接找到这个标签,当然也可以先找到div标签中的class属性是main-inage,再找到img的src属性,这里我就采用第一种方法。

    def get_img_url(url, name):
        html = get_html(url)
        soup = BeautifulSoup(html, 'lxml')
        img_url = soup.find('img', alt= name)
        return img_url['src']

    将图片存入本地

      得到图片url链接之后要讲图片存到本地,在请求图片url的时候要加入Picreferer,否则网站会认为你是一个爬虫,会返还给你一个盗链图

    该方法传入的参数有3个,第一个是图片url,第二个当前图片的页数,用作创建文件,第三个是图集名称,在存储之前先创建了一个名称是图集名称的文件夹,这样就能将图片存入指定文件夹

    def save_img(img_url, count, name):
        req = requests.get(img_url, headers=Picreferer)
        with open(name+'/'+str(count)+'.jpg', 'wb') as f:
            f.write(req.content)

    爬取一个图集完整代码

    import requests
    from bs4 import BeautifulSoup
    import os
    
    Hostreferer = {
        'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
        'Referer':'http://www.mzitu.com'
    }
    Picreferer = {
        'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
        'Referer':'http://i.meizitu.net'
    }
    
    def get_page_name(url):#获得图集最大页数和名称
        html = get_html(url)
        soup = BeautifulSoup(html, 'lxml')
        span = soup.findAll('span')
        title = soup.find('h2', class_="main-title")
        return span[10].text, title.text
    
    def get_html(url):#获得页面html代码
        req = requests.get(url, headers=Hostreferer)
        html = req.text
        return html
    
    def get_img_url(url, name):
        html = get_html(url)
        soup = BeautifulSoup(html, 'lxml')
        img_url = soup.find('img', alt= name)
        return img_url['src']
    
    def save_img(img_url, count, name):
        req = requests.get(img_url, headers=Picreferer)
        with open(name+'/'+str(count)+'.jpg', 'wb') as f:
            f.write(req.content)
    
    def main():
        old_url = "http://www.mzitu.com/123114"
        page, name = get_page_name(old_url)
        os.mkdir(name)
        for i in range(1, int(page)+1):
            url = old_url + "/" + str(i)
            img_url = get_img_url(url, name)
            #print(img_url)
            save_img(img_url, i, name)
            print('保存第' + str(i) + '张图片成功')
    main()

      在main方法中先请求到图集的名称和最大页数,并且使用名称创建一个文件夹来存储图片。再从1到最大页数做一个for循环,

    然后图片的每一页是     图集首页 + / + 当前页数,得到含有图片内容的url链接,后面就可以将得到图片存入本地。

    爬取结果

      文件夹名称即为图集名称,内部图片以页数作为文件名。

    下面准备开始多个页面的爬取,先将前面爬取一个图集的方法进行封装

    爬取一个图集

    在进行爬取一个图集前先加入一个方法,在爬取图集名称的时候,由于名称的字符不限,所以可能出现含有文件夹中不能出现的一些字符,例如:/ : ? < > 等

    所以需要将前面的代码进行修改,加入一个rename方法,将这些字符换成可行的字符。(在这里我就直接将这些字符去掉)

    这里采用re库,将name中含有的非法字符换成空,可以看做直接去掉。

    import re
    def rename(name):
        rstr = r'[/\:*?<>|]'
        new_name = re.sub(rstr, "", name)
        return new_name
    
    def save_one_atlas(old_url):
        page, name = get_page_name(old_url)
        new_name = rename(name)
        os.mkdir(new_name)
        
        print("图集--" + name + "--开始保存")
        for i in range(1, int(page)+1):
            url = old_url + "/" + str(i)
            img_url = get_img_url(url, name)
            # print(img_url)
            save_img(img_url, i, name)
            print('正在保存第' + str(i) + '张图片')
        print("图集--" + name + "保存成功")

    爬取一整页图集

    def get_atlas_list(url):
        req = requests.get(url, headers=Hostreferer)
        soup = BeautifulSoup(req.text, 'lxml')
        atlas = soup.find_all(attrs={'class':'lazy'})
        atlas_list = []
        for atla in atlas:
            atlas_list.append(atla.parent['href'])
        return atlas_list

    分析一个页面中的url链接,发现如果找 target="_blank" 这一属性,则会产生很多多余的链接,所以我直接从字标签入手找到属性 class="lazy"的img标签,然后再在寻找到img标签的父标签中的href

    def save_one_page(start_url):
        atlas_url = get_atlas_list(start_url)
        for url in atlas_url:
            save_one_atlas(url)

    将爬取一整夜图集进行封装,方便后续的翻页爬取

    翻页爬取

    分析页面url,发现每一页均是初始网址+page/+页数/

    第一页是初始网址,但是页数为1的链接也是直接进入第一页,所以所有页的url就可以用以上通式改变页数进行遍历。

    start_url = "http://www.mzitu.com/"
        for count in range(1, 3):
            url = start_url + "page/" + str(count) +"/"
            save_one_page(url)

    这里作为测试,所以只爬取前两页图集。改变range内的参数,即可改变爬取页数。

    完整代码

     1 import requests
     2 from bs4 import BeautifulSoup
     3 import os
     4 import re
     5 
     6 Hostreferer = {
     7     'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
     8     'Referer':'http://www.mzitu.com'
     9 }
    10 Picreferer = {
    11     'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
    12     'Referer':'http://i.meizitu.net'
    13 }
    14 
    15 def get_page_name(url):#获得图集最大页数和名称
    16     html = get_html(url)
    17     soup = BeautifulSoup(html, 'lxml')
    18     span = soup.findAll('span')
    19     title = soup.find('h2', class_="main-title")
    20     return span[10].text, title.text
    21 
    22 def get_html(url):#获得页面html代码
    23     req = requests.get(url, headers=Hostreferer)
    24     html = req.text
    25     return html
    26 
    27 def get_img_url(url, name):
    28     html = get_html(url)
    29     soup = BeautifulSoup(html, 'lxml')
    30     img_url = soup.find('img', alt= name)
    31     return img_url['src']
    32 
    33 def save_img(img_url, count, name):
    34     req = requests.get(img_url, headers=Picreferer)
    35     new_name = rename(name)
    36     with open(new_name+'/'+str(count)+'.jpg', 'wb') as f:
    37         f.write(req.content)
    38 
    39 def rename(name):
    40     rstr = r'[/\:*?<>|]'
    41     new_name = re.sub(rstr, "", name)
    42     return new_name
    43 
    44 def save_one_atlas(old_url):
    45     page, name = get_page_name(old_url)
    46     new_name = rename(name)
    47     os.mkdir(new_name)
    48     
    49     print("图集--" + name + "--开始保存")
    50     for i in range(1, int(page)+1):
    51         url = old_url + "/" + str(i)
    52         img_url = get_img_url(url, name)
    53         # print(img_url)
    54         save_img(img_url, i, name)
    55         print('正在保存第' + str(i) + '张图片')
    56     print("图集--" + name + "保存成功")
    57 
    58 
    59 def get_atlas_list(url):
    60     req = requests.get(url, headers=Hostreferer)
    61     soup = BeautifulSoup(req.text, 'lxml')
    62     atlas = soup.find_all(attrs={'class':'lazy'})
    63     atlas_list = []
    64     for atla in atlas:
    65         atlas_list.append(atla.parent['href'])
    66     return atlas_list
    67 
    68 def save_one_page(start_url):
    69     atlas_url = get_atlas_list(start_url)
    70     for url in atlas_url:
    71         save_one_atlas(url)
    72 
    73 
    74 if __name__ == '__main__':
    75     start_url = "http://www.mzitu.com/"
    76     for count in range(1, 3):
    77         url = start_url + "page/" + str(count) +"/"
    78         save_one_page(url)
    79     print("爬取完成")
    View Code

    这个程序能够爬取图片,但是效率太低,正在学习多进程,希望之后可以提高该程序的爬取效率。

    我爬了3个多G的图片花了我接近4个小时,足以证明效率是真的低。

    并且在爬取过程中出现一个问题,提示 你的主机中的软件中止了一个已建立的连接 ,这个问题还未找到解决方法,也未找明产生的具体原因。

    这是我写的第一篇较长的博客,还有很多未完善的地方,希望大家见谅。

  • 相关阅读:
    bzoj3676 [Apio2014]回文串
    bzoj4199 [Noi2015]品酒大会
    bzoj3171 [Tjoi2013]循环格
    bzoj4709 [Jsoi2011]柠檬
    bzoj2668 [cqoi2012]交换棋子
    bzoj1458 士兵占领
    25号搜索的一些例子,。。Oil Deposits&&Red and Black&&Knight Moves&&Catch That Cow&&Tempter of the Bone
    第一次超水(我错了,有难度的)的组队赛!!!The Coco-Cola Store &&Multiple of 17&& Box Game
    博弈 7月24号:HDU 2176(Nim博弈)
    2013年7月23号:大数的加与乘I-number&&Power of Cryptography
  • 原文地址:https://www.cnblogs.com/forever-snow/p/8506746.html
Copyright © 2011-2022 走看看