mm131爬虫与图片下载

前言

  1. 爬取数据时不要随意打开存储文件,否则会造成数据写入失败。
  2. 由于没有多线程等,速度会慢一些。Total data: (2000 - 3000)
  3. 爬虫的数据存储主要是 pandas 的 DataFrame。
  4. 网站无益,使用者自重。
  5. 到目前为止,也只见其更换图片库源的域名。
  6. 详情自行搜索。。。

MM131 图片爬取

  1. 爬取网站数据,并建立本地的Excel数据表格


    Data-catalog.PNG
  2. 输入搜索内容名称(仅搜标题名称)


    Search-result.PNG
  3. 内容确认并下载(这里是看不到图的,需要的请自行优化)


    Download-info.PNG
  4. 下载完成的文件夹展示(其他原因,这里仅展示部分)


    Image-example.PNG

网站页面数据爬取(mm131.py)

from requests import get
from lxml import etree
from item import Item
from urllib import parse
from os.path import join
import re
import time


class MM131(object):
    url = "https://m.mm131.net"

    def __init__(self, path, nav_items_name="nav_items.xlsx", data_name="img_data.xlsx"):
        self.nav_items = Item(join(path, nav_items_name))
        self.img_items = Item(join(path, data_name))
        self.nav_items.get_Frame(["类型名称", "网址", "页数", "编号"])
        self.img_items.get_Frame(["标题", "网址", "编号", "页数", "类型名称"])

    @staticmethod
    def get(url, decode="gbk"):
        cont = get(url=url)
        return cont.content.decode(decode)

    @staticmethod
    def get_list_url(url, type_num, page):
        return parse.urljoin(url, "list_{}_{}.html".format(type_num, str(page)))

    def parse_nav(self):
        items = []
        parser = etree.HTML(self.get(self.url))
        nav_items = parser.xpath("//nav[@class='slide-menu']/ul/li[@class='dropdown']"
                                 "/ul//li[contains(@class,'cat-item')]")

        for nav in nav_items:
            try:
                # 作为添加参数的 key
                type_url = nav.xpath("a/@href")[0]
                if type_url == "https://m.mm131.net/app":
                    continue
                type_name = nav.xpath("a/text()")[0]
                items.append([type_name, type_url])
            except IndexError as e:
                pass

        return items

    def parse_list_info(self, url, item):
        parser = etree.HTML(self.get(url))
        content = parser.xpath("//content[@id='content']")

        if len(content) != 0:
            # 各类型列表页数
            pages = content[0].xpath("nav//span[@id='spn']/text()")
            if len(pages) != 0:
                page_res = re.findall(r"\d+", pages[0])
                total_page = page_res[1] if len(page_res) != 0 else 0
                item.append(str(total_page))
            # 列表的类型编号
            type_num = content[0].xpath("nav//a[@id='xbtn']/@href")
            if len(type_num) != 0:
                num_res = re.findall(r"\d+", type_num[0])
                type_num = num_res[0] if len(num_res) != 0 else 0
                item.append(str(type_num))

        return item

    def parse_nav_info(self):
        items = self.parse_nav()
        for inx, nav in enumerate(items):
            self.nav_items.append(nav + ['0', '0'] if inx == 0 else self.parse_list_info(nav[1], nav))
        self.nav_items.save()
        return self.nav_items.get_data()

    def parse_list_detail(self, url, type_name):
        parser = etree.HTML(self.get(url))
        content = parser.xpath("//content[@id='content']")
        if len(content) != 0:
            articles = content[0].xpath("article[@class='post']")
            for article in articles:
                try:
                    title = article.xpath("div[@class='post-header']/h2/a/text()")[0]
                    p_url = article.xpath("div[@class='post-header']/h2/a/@href")[0]
                    av = p_url[p_url.rfind('/') + 1: p_url.rfind('.')]
                    self.img_items.append([title, p_url, str(av),
                                           str(self.parse_detail_page(p_url)),
                                           type_name], str(av), 2)
                except IndexError as e:
                    continue
            self.img_items.show()
            self.img_items.save()

    def parse_detail_page(self, url):
        parser = etree.HTML(self.get(url))
        articles = parser.xpath("//article")
        if len(articles) != 0:
            pages = articles[1].xpath("div[@class='paging']/span/text()")
            pages = pages[0] if len(pages) != 0 else ''
            page_res = re.findall(r"\d+", pages)
            return page_res[1] if len(page_res) != 0 else 0

    def parse_type_detail_info(self, pos):
        ni = self.nav_items
        name = ni.get_data()[pos, 0]
        for i in range(1, int(ni.get_data()[pos, 2]) + 1):
            print("开始获取 第{}页 信息".format(i))
            t_url = self.get_list_url(ni.get_data()[pos, 1], ni.get_data()[pos, 3], i)
            self.parse_list_detail(t_url, name)
            time.sleep(2)

    def start(self):
        self.parse_nav_info()
        for i in range(0, len(self.nav_items.get_data())):
            print("类型 {}:".format(i))
            self.parse_type_detail_info(i)
            time.sleep(5)


if __name__ == '__main__':
    mm = MM131("./")
    mm.start()

网站页面数据的存储类(item.py)

from pandas import DataFrame
from pandas import read_excel
from os.path import exists
import numpy as np


def trans_arr(obj):
    return list(obj.values())


class Item(object):
    df: DataFrame
    df_title = []
    save_counter = 0

    def __init__(self, path="./Default.xlsx"):
        self.path = path

    def get_Frame(self, title_arr):
        res = self.load()
        if not res:
            self.df_title = title_arr
            self.df = DataFrame(columns=title_arr)

    def get_col_name(self, col):
        ct = type(col)
        col_name = ''

        if ct == int:
            col_name = self.df_title[col]
        elif ct == str:
            col_name = ct

        return col_name

    # Axis :: [Row: 0 && Column: 1]
    def get_len(self, axis):
        return self.df.shape[axis]

    def get_df(self):
        return self.df

    def get_data(self):
        return np.array(self.df)

    def set_index(self, col_name):
        self.df = self.df.set_index(col_name, drop=False)

    def set_path(self, path):
        self.path = path

    def pop(self, col, items):
        col_name = self.get_col_name(col)
        self.set_index(col_name)
        self.df = self.df.drop(items)

    def data_only(self, data, col_inx):
        return data in self.df.iloc[:, col_inx].values

    def append(self, data_arr, check=None, col_inx=None):
        if check is not None and col_inx is not None:
            if self.data_only(check, col_inx):
                return False

        self.df.loc[self.df.shape[0]] = data_arr
        return True

    def load(self):
        res = exists(self.path)
        if res:
            data = read_excel(self.path)
            self.df = DataFrame(data)
        return res

    def save(self):
        self.save_counter += 1
        self.df.to_excel(self.path, index=False)
        print('\n', '保存次数:', self.save_counter, '\n')

    def show(self):
        print(self.df.iloc[:, :])

爬取后的数据以xlsx表格存储。

根据爬取的数据进行图片下载

  1. 具体的图片爬取时,网站默认会自动使用第二张图片进行填充,如果不是正在打开的那张图片页面的话。
  2. 后来直接从网页进行请求,发现该网页的请求头会带有 'Referer': "https://m.mm131.net/"。请求头附加上这个便可以切换回原来的图片进行下载。
  3. 这里的 sleep 是防止过快的爬取图片。在利用和改造网络请求的同时,也要呵护,尊重,保护运营方的服务环境。
# coding: utf8
import requests
from os.path import join
from openpyxl.reader.excel import load_workbook
import re
import os


class MM131ItemLoader(object):
    max_row = 0
    max_col = 0
    data = []

    def __init__(self, path, name):
        self.path = path
        self.name = name
        self.book = self.load_book(self.path, self.name)
        self.sheet = self.book.active
        if self.sheet:
            self.max_row = self.sheet.max_row
            self.max_col = self.sheet.max_column

    def load_book(self, path, name):
        self.book = load_workbook('{}.xlsx'.format(join(path, name)))
        return self.book

    def match(self, p_col, val, num=None):
        if len(val) == 0:
            return
        for row in range(2, num if num and 0 < num < self.max_row else self.max_row + 1):
            s_val = self.sheet.cell(row, p_col).value
            res = re.findall(r".*{}.*".format(val), s_val)
            if len(res) == 0:
                mr = ""
                for s in val:
                    mr += "{}.*".format(s)
                mc = re.compile(mr)
                res = re.findall(mc, s_val)
            if len(res) != 0:
                temp = []
                for col in range(1, self.max_col + 1):
                    temp.append(self.sheet.cell(row, col).value)
                self.data.append(temp)

    def get_items(self):
        return self.data


class MM131ImageDownloader(MM131ItemLoader):
    def __init__(self, path, name, save_path):
        super().__init__(path, name)
        self.path = path
        self.save_path = join(save_path, "mm131")
        self.origin_path = os.getcwd()
        if not os.path.exists(self.save_path):
            os.mkdir(self.save_path)
        os.chdir(self.save_path)

    def set_excel_path(self, path):
        self.path = path

    def set_save_path(self, save_path):
        self.save_path = save_path

    @staticmethod
    def download_img(img_url, path, name):
        print("图片地址:", img_url)
        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; "'
                                 '"Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0',
                   'Referer': "https://m.mm131.net/"}
        r = requests.get(img_url, headers=headers, stream=True)
        if r.status_code == 200:
            open(join(path, name), 'wb').write(r.content)  # 将内容写入图片
            print("请求成功")
        else:
            print("请求失败")

    @staticmethod
    def get_img_url(av, page):
        """
        2020: img1.mmmw.net
        2021: img1.nthjjz.com
        """
        return "https://img1.nthjjz.com/pic/{}/{}.jpg".format(str(av), str(page))

    def download(self, av, page, name, path):
        url = self.get_img_url(av, page)
        path = join(self.save_path, path) if path else self.save_path
        self.download_img(url, path, name)

    def download_match(self, val, num=None):
        self.match(1, val, num)
        print("关键词搜索: {}".format(val))
        items = self.get_items()
        if len(items) == 0:
            print("暂无此搜索记录")
            return
        else:
            print("已经找到 {} 条, 准备下载。。。".format(len(items)))

        ir = input("是否现在下载? (Y/N) ")
        if ir.upper() == "Y":
            for (inx, item) in enumerate(items):
                title = item[0]
                img_type = item[4]
                if not os.path.exists(img_type):
                    os.mkdir(img_type)
                os.chdir(img_type)
                if not os.path.exists(title):
                    os.mkdir(title)
                    os.chdir(self.save_path)
                else:
                    os.chdir(self.save_path)
                    continue
                i_path = join(self.save_path, img_type, title)
                av = item[2]
                pages = int(item[3])
                print("{}. {}\t[准备下载]".format(str(inx + 1), title))
                for page in range(1, pages + 1):
                    self.download(av, page, "{}.jpg".format(page), i_path)
        else:
            im = input("喵喵,还需要继续搜索吗? (Y/N)")
            if im.upper() == "Y":
                self.data = []
                val = input("请输入搜索词:")
                self.download_match(val, num)
            else:
                print("喵喵 ! ! !")


if __name__ == '__main__':
    # MM131ImageDownloader(xlsx文件存储路径, xlsx文件名, 图片存储路径)
    mm = MM131ImageDownloader("./", "img_data", "D:/")
    mm.download_match("沐")
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容