吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 823|回复: 4
收起左侧

[Python 原创] Scrapy项目练习 某an手机壁纸

[复制链接]
qfmy2024 发表于 2024-8-18 15:37

Scrapy

Scrapy官网

Scrapy | A Fast and Powerful Scraping and Web Crawling Framework  https://scrapy.org/

清华大学某Scrapy相关PDF,建议参考学习:

http://www.tup.tsinghua.edu.cn/upload/books/yz/094461-01.pdf

Result

image_wB5K95R7HC.png

image_DsfN7n1DTz.png

Step

1、创建虚拟环境

创建爬虫专用的Python虚拟环境,Python版本随意,这里我选择的是Python3.10,虚拟环境管理工具使用的是anaconda,

image_cXzj8vaAh4.png

conda create -n Crawler python=3.10 scrapy此命令创建名称为Crawler的虚拟环境,Python版本为3.10,同时安装scrapy第三方依赖。

当然,还可以选择使用Python自带的venv创建虚拟环境,请自行百度解决。

2、选择一个你喜欢的目录,打开cmd,激活Crawler虚拟环境,使用命令生成项目

# 激活虚拟环境
conda activate Crawler
# 创建Scrapy爬虫项目
scrapy startproject NetBiAnSpider
# 进入项目
cd NetBiAnSpider
# 生成爬虫,指定名称允许爬取的域名
scrapy genspider netbian target_domain

3、相关代码

目录结构如下图所示:

image_zoFrIlQ3Km.png

items.py

class NetbianspiderItem(scrapy.Item):
    src = scrapy.Field()
    alt = scrapy.Field()

spider/netbian.py

import logging

import scrapy

from NetBiAnSpider.items import NetbianspiderItem

class NetbianSpider(scrapy.Spider):
    name = "netbian"
    # 某an手机壁纸域名
    allowed_domains = [""]
    # 某an手机壁纸通用分页请求地址
    start_urls = [""]
    finish_category = []  # 完成的分类列表
    current_category = "动漫"
    current_page = 0

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.classes = {
            # '全部': 2,
            '动漫': 24, '游戏': 25, '美女': 26, '风景': 33, '动物': 35, '文字': 51, '帅哥': 44,
            '汽车': 34, '新年': 36, '鬼刀': 37, '集原美': 38, '英雄联盟': 39, '王者荣耀': 41, '影视': 42, '苹果': 43,
            '女生专用': 45, '宗教': 46, '节日': 47, '可爱': 48, '正能量': 49, '系统': 50, '情侣': 52, '简约': 53,
            # '独家': 56,  # 独家没了
        }
        self.keys = self.classes.keys()
        self.log(f"当前所有关键字列表为:{self.keys}", logging.INFO)

    def parse(self, response):
        if len(response.body) == 0:
            self.logger.info(f"当前分类{self.current_category},共{self.current_page - 1}页,已到达最后一页")
            self.finish_category.append(self.current_category)
            self.current_page = 0
            for key in self.keys:
                if key not in self.finish_category:
                    self.current_category = key
                    yield from self.next()  # 需要yield from,Chat GPT说的,不然不行,自行百度,俺也不会用yield
                    self.logger.info(f"当前分类{self.current_category},第{self.current_page}页")
                    break
        else:
            self.current_page += 1
            yield from self.next()  # 这样写就能继续处理后续生产的请求了,yield俺也不常用,问的chatGPT
            self.logger.info(f"当前分类{self.current_category},第{self.current_page}页")
        images = response.xpath('//li/a/img')
        item = NetbianspiderItem()
        for image in images:
            src = image.xpath('@src').get()
            alt = image.xpath('@alt').get()
            item['src'] = src
            item['alt'] = alt
            yield item

    def next(self):
        # 某an手机壁纸通用分页请求地址
        url = f""
        self.logger.info(url)
        yield scrapy.Request(url, callback=self.parse)

pipelines.py

import datetime
import logging
import re

import pymysql
from pymysql import IntegrityError, OperationalError

import settings

# useful for handling different item types with a single interface
class NetbianspiderPipeline:
    def __init__(self):
        self.db_conn = None
        self.db_cur = None
        try:
            self.db_conn = pymysql.connect(host=settings.HOST, port=settings.PORT, user=settings.USERNAME, password=settings.PASSWORD, database=settings.DATABASE, charset='utf8', use_unicode=True)  # 连接数据库
            self.db_cur = self.db_conn.cursor()  # 创建游标
            logging.info("数据库连接成功")
        except OperationalError as e:
            logging.error(e)

    def process_item(self, item, spider):
        if not self.db_cur:  # 判断是否获取到数据库游标
            return item
        preview = item['src']
        u = preview[:-14] + ".jpg"
        img_url = u.replace("small", "")  # 去掉前面的small,然后去掉.jpg前面的十位即为大图url
        match = re.search(r"/(\d{4})/(\d{2})(\d{2})/", u)  # 提取URL中的日期 年月日
        year, mouth, day = match.group(1), match.group(2), match.group(3)
        dt = datetime.datetime(year=int(year), month=int(mouth), day=int(day))  # 转为datetime对象
        values = (item['alt'], preview, img_url, dt)
        sql = "insert into wallpaper(title,preview,url,create_at) values (%s,%s,%s,%s)"  # 为SQL语法,数据顺序要和建表一致
        try:
            self.db_cur.execute(sql, values)
            self.db_conn.commit()
        except IntegrityError:
            logging.info(f"此记录已存在: {preview}")
        return item

    def close_spider(self, spider):
        if self.db_cur:
            self.db_cur.close()  # 关闭游标
        if self.db_conn:
            self.db_conn.close()  # 关闭数据库

settings.py

# 启用管道将数据存入数据库
ITEM_PIPELINES = {
    "NetBiAnSpider.pipelines.NetbianspiderPipeline": 300,
}

# Log
LOG_LEVEL = 'INFO'
today = datetime.datetime.now()
log_file_path = f'log/scrapy_{today.year}_{today.month}_{today.day}.log'
LOG_FILE = log_file_path

# Database
HOST = "localhost"
PORT = 3306
USERNAME = "root"
PASSWORD = "root"
DATABASE = "wallpaper"

wallpaper.wallpaper DDL

CREATE TABLE `wallpaper` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `title` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
  `preview` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
  `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
  `create_at` date DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `wallpaper_unique` (`preview`)
) ENGINE=MyISAM AUTO_INCREMENT=8555 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

4、运行爬虫

scrapy runspider netbian

没啥大问题就能看到类似输出

TODO

  • [ ] 增量式爬取
  • [ ] 关键信息写入日志
  • [ ] 邮件发送
  • [ ] 定时执行
  • [ ] 改进工程,新增其他类似网站爬虫

End

我的Python爬虫的学习路线是从正则表达式(re库)提取数据,再到BeautifulSoup(pip install beautifulsoup4),再到lxml,最后就是爬虫框架,框架适合大型项目,平时使用requests+lxml更多,随机请求头工具可以使用fake_useragent(pip install fake_useragent),代{过}{滤}理的话GitHub上有个大佬写的开源代{过}{滤}理,挺好用的。最后,希望这个项目对各位有帮助。(其实我是来水52的帖的,之前号被清了,后面开放注册有重新注册回来了,这次悠着点,手动狗头)

GitHub - jhao104/proxy_pool: Python ProxyPool for web spider Python ProxyPool for web spider. Contribute to jhao104/proxy_pool development by creating an account on GitHub. https://github.com/jhao104/proxy_pool

免费评分

参与人数 1吾爱币 +7 热心值 +1 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

sunke5616 发表于 2024-8-18 22:20
有效果图可以参考看一下麻
xhtdtk 发表于 2024-8-18 23:07
增量式爬取是异步爬取吗,当初想学scrapy就是想异步,听完一个流程没发现怎么弄,去学async和aiohttp,过程虽然遇到问题但都解决了,所以还是搞不懂scrapy如何异步
 楼主| qfmy2024 发表于 2024-8-19 22:28
sunke5616 发表于 2024-8-18 22:20
有效果图可以参考看一下麻

有的,效果图就是存入数据库嘛,将大图和预览URL存入数据库,需要在设置里面启用中间件,我使用的是MySQL数据库,需要安装mysql驱动,
[Bash shell] 纯文本查看 复制代码
pip install pymysql
微信图片_20240819222547.png
 楼主| qfmy2024 发表于 2024-8-19 22:37
本帖最后由 qfmy2024 于 2024-8-19 22:38 编辑
xhtdtk 发表于 2024-8-18 23:07
增量式爬取是异步爬取吗,当初想学scrapy就是想异步,听完一个流程没发现怎么弄,去学async和aiohttp,过程 ...

这个是Scrapy的执行流程图,怎么说呢,刚开始我也不太懂Scrapy,也难以理解,不过爬虫无非就是获取请求,提权HTML中的数据,然后清洗数据,保存数据,以及进一步请求下一页。增量式爬虫是指只获取和保存新的数据,对之前就保存过的数据不再进行保存。异步其实是和同步相对的一个概念,异步处理时不会阻塞当前线程,同步则会阻塞线程,等处理完等待的内容后才会执行后面的代码,简单来讲同步比异步效率低,以上只是我个人理解,还望路过的大佬指正
1526ee25ccd79cf14129a459fe027b55.png
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 13:08

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表