京东图书爬虫可视化项目

    科技2025-09-15  65

    一、项目准备

    开发环境: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 访问链接http://127.0.0.1:8000/admin

    三、爬取图书数据

    1.爬取分析

    京东所有图书的总入口 : https://book.jd.com/booksort.html解析大分类的名字 - 52个大分类解析小分类名字和链接 - 882个小分类 每个小分类的图书列表url,如:中国当代小说 https://list.jd.com/list.html?cat=1713,3258,3297 解析列表页所有的书,遍历解析每本书的详细信息 翻页的网址page: https://list.jd.com/list.html?cat=1713%2C3258%2C3297&page=3&s=53&click=0解析下一页的网址,如果没有值,代表当前小分类抓取完毕

    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, }
    Processed: 0.010, SQL: 8