京东图书爬虫可视化项目

一、项目准备

  • 开发环境:python3
  • 开发工具:pycharm
  • 使用技术:Scrapy + Django + PyMySQL

二、图书管理系统

1.创建项目

  • 创建Django项目
django-admin startproject web_book(项目名称)
  • 创建子应用
cd web_book
python manage.py startapp book(子应用名称)
  • 注册子应用:在settings.py文件中,INSTALLED_APPS项中进行子应用注册
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 注册子应用
    'book.apps.BookConfig',
]

2.MySQL配置

  • 1、安装myaqi驱动程序PyMySQL
pip install PyMySQL
  • 2、导入pymsql并创建实例化对象:在Django的工程同名子目录的__init__.py文件中添加如下语句。
from pymysql import install_as_MyAQLdb

install_as_MySQLdb()
  • 3、配置MySQL信息:在Django的工程同名子目录的settings.py文件中修改DATABASES配置信息
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1',  # 数据库主机
        'PORT': 3306,  # 数据库端口
        'USER': 'root',  # 数据库用户名
        'PASSWORD': '123456',  # 数据库用户密码
        'NAME': 'book'  # 数据库名字
    }
}
  • 4、登陆MySQL客户端
 mysql -u root -p
  • 5、在MySQL中创建数据库book
create database book charset=utf8;

3.创建图书模型类

  • 创建模型类:book/models.py
from django.db import models


class BookInfo(models.Model):
    # 数据存储内容:大分类、小分类、书名、作者、出版社、价格、默认图片
    category = models.CharField(max_length=50, default="大类", verbose_name="图书大类")
    small_category = models.CharField(max_length=50, default="小类", verbose_name="图书小分类")
    name = models.CharField(max_length=100, default="无", verbose_name="书名")
    author = models.CharField(max_length=50, default="无", verbose_name="作者")
    store = models.CharField(max_length=100, default="无", verbose_name="出版社")
    pub_date = models.CharField(max_length=30, null=True, verbose_name="出版时间")
    price = models.DecimalField(decimal_places=2, max_digits=10, default="0.00", verbose_name="价格")
    default_image = models.ImageField(null=True, verbose_name="图片")
    
    class Meta:
        verbose_name = "图书"
        verbose_name_plural = verbose_name
        
    def __str__(self):
        return self.name
  • 执行数据迁移和mysql数据库同步
cd web_book
python manage.py makemigrations
python manage.py migrate

4.Admin站点配置

  • 设置项目本地化
# 使用中国语言
LANGUAGE_CODE = 'zh-hans'
# 使用上海时间
TIME_ZONE = 'Asia/Shanghai'
  • 创建超级管理员用户
    • 用户名
    • 密码:至少8位,数字和字母混合使用
    • 邮箱:符合邮箱格式即可
python manage.py createsuperuser
  • 后台站点配置:admin.py
from django.contrib import admin
from .models import BookInfo


# 自定义 管理类
class BookInfoAdmin(admin.ModelAdmin):
    # 列表页显示的内容
    list_display = ['id', "category", "small_category", 'name', "author", "store", "price"]


# 注册模型类
admin.site.register(BookInfo, BookInfoAdmin)
admin.site.site_header = '小七书城'
admin.site.site_title = '小七书城MIS'
admin.site.index_title = '欢迎使用小七书城MIS'
  • 启动后台服务器
python manage.py runserver

三、爬取图书数据

1.爬取分析

2.数据清洗解析 - xpath

  • 图书首页
start_urls = "https://book.jd.com/booksort.html"
  • 图书大分类提取
# 获取所有大分类标签 dt
dt_list = '//*[@id="booksort"]/div[2]/dl/dt'
# 遍历52个大分类
for dt in dt_list:
	# 解析大分类的名字
	category = dt.xpath('./a/text()')
  • 图书小分类提取
	# 根据大分类取小分类
	em_list = './following-siblings::*[1]/em'
	for em in em_list:
		# 解析小分类的名字
		small_category = './a/text()'
		# 解析小分类的链接,注意:需要进行拼接
		small_link = 'http:' + "./a/@href"

  • 图书列表图书信息提取
# 解析列表页中所有的书
list_book = '//*[@id="J_goodsList"]/ul/li/div'
# 遍历解析每本书的详细信息
for book in list_book:
	# 书名
	name = ".//div[@class='p-name']/a/em/text()"
	# 作者
	author = ".//div[@class='p-bookdetails']/span[@class='p-bi-name']/a/text()"
	# 出版社
	store = ".//div[@class='p-bookdetails']/span[@class='p-bi-store']/a/text()"
	# 价格
	price = ".//div[@class='p-price']/strong/i/text()"
	# 图片地址
	default_image = ".//div[@class='p-img']/a/img/@src"
  • 提取列表页的翻页链接
next_url = ".//a[@class='pn-next']/@href"

3.实现爬取

  • 3.1创建爬虫项目:
    • 创建项目:scrapy startproject BOOK
    • 进入项目:cd BOOK
    • 创建爬虫:scrapy genspider book jd.com
    • 运行爬虫:scrapy crawl book
  • 3.2 爬虫项目配置:settings.py
# 设置用户代理
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36'

# 不遵守君子协议
ROBOTSTXT_OBEY = False
  • 3.3 爬虫爬取实现
class BookSpider(scrapy.Spider):

    name = 'book' # 爬虫名字
    allowed_domains = ['jd.com', 'p.3.cn'] # 允许爬取的域名范围
    start_urls = ['https://book.jd.com/booksort.html'] # 爬取的开始页面

    page = 0

    # 解析第一层的 大分类名字
    def parse(self, response):
        # 解析 大分类的名字 --- 52
        dt_list = response.xpath('//*[@id="booksort"]/div[2]/dl/dt[1]')

        # 解析 小分类的名字  和 链接 ---880
        # 遍历 所有的dt 标签, 使用xpath  follwing-sibling::*[1] 取出下一节点的 平级元素 dd
        for dt in dt_list:
            item = {}
            item['category'] = dt.xpath('a/text()').extract_first()

            # 小分类
            em_list = dt.xpath('./following-sibling::*[1]/em')
            for em in em_list[:1]:
                item['small_category'] = em.xpath('a/text()').extract_first()
                small_link = 'https:' + em.xpath('a/@href').extract_first()

                # 发送 图书列表页请求 第二层
                yield scrapy.Request(small_link, callback=self.parse_book, meta={'book': deepcopy(item)})
     # 解析 列表页的 图书
    def parse_book(self, response):
        # 接收从 上一页 传入的item
        item = response.meta['book']
        # 取出所有的图书 book_list
        book_list = response.xpath('//div[@id="plist"]/ul/li')

        for book in book_list[:1]:
            # 1.图书图片
            item['default_image'] = "https:" + book.xpath('.//div[@class="p-img"]/a/img/@src').extract_first()
            # 2.图书名字
            item['name'] = book.xpath('.//div[@class="p-name"]/a/em/text()').extract_first().strip()
            # 3.作者
            item['author'] = book.xpath('.//span[@class="author_type_1"]/a/text()').extract_first()
            # 4.出版社
            item['store'] = book.xpath('.//span[@class="p-bi-store"]/a/text()').extract_first()
            # 5.出版时间
            item['time'] = book.xpath('.//span[@class="p-bi-date"]/text()').extract_first().strip()

            item['price'] = book.xpath('.//div[@class="p-price"]/strong/i/text()').extract_first()
            # 价格--第二次发请求回来ajax无刷新实现的
            # item['book_price'] = book.xpath('.//div[@class="p-price"]/strong/i/text()').extract_first()
            """
                https://p.3.cn/prices/mgets?skuIds=J_11757834
            """
            # 获取图书id
            book_id = book.xpath('./div/@data-sku').extract_first()
            # 拼接价格的url
            price_url = 'https://p.3.cn/prices/mgets?skuIds=J_{}'.format(book_id)

            # 发送价格的请求
            yield scrapy.Request(price_url, callback=self.parse_price, meta={'book': deepcopy(item)})

    # 解析价格
    def parse_price(self, response):
        item = response.meta['book']
        item['price'] = json.loads(response.body.decode())[0]['p']

        yield item
         # 只爬取 前5页
        self.page += 1
            if self.page > 4:
                return

        # 列表翻页
        # 1. 取出  下一页 标签 的 URL 网址不齐全
        next_url = response.xpath('//a[@class="pn-next"]/@href').extract_first()

        # 2. 发送 下一页的请求 可以
        if next_url: # 判断结束 如果 next_url 为none 就结束了
            yield response.follow(
                next_url,
                callback=self.parse_book,
                meta={'book': item}
            )
  • 3.4 存储数据库:
    • 3.4.1 在pipeline.py文件中使用pipeline将爬取的数据入库
from pymysql import connect
from jdBook import settings


class JdbookPipeline(object):

    def open_spider(self, spider):
        self.client = connect(
            host=settings.MYSQL_HOST,
            user=settings.MYSQL_USER,
            password=settings.MYSQL_PASSWORD,
            database=settings.MYSQL_DB_NAME,
            charset="utf8",
        )
        # 创建游标对象
        self.cur = self.client.cursor()

    def process_item(self,item,spider):
        try:
            values = (
                None,
                item["category"],
                item["small_category"],
                item["name"],
                item["author"],
                item["store"],
                item["pub_date"],
                item["price"],
                item["default_image"],
            )
            print(values)
            sql = "insert into book.book_bookinfo values (%s,%s,%s,%s,%s,%s,%s,%s,%s);"
            self.cur.execute(sql, values)
            # 提交sql语句
            self.client.commit()
        except Exception as e:
            # 打印错误日志
            print(e)

        return item

    def close_spider(self,spider):
        self.client.close()

  • 3.4.2 在settings.py文件中开启pipeline
ITEM_PIPELINES = {
	"BOOK.pipelines.BookPipeline":300,
}
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值