python利用xpath爬取网上数据并存储到django模型中


Posted in Python onFebruary 26, 2021

帮朋友制作一个网站,需要一些产品数据信息,因为是代理其他公司产品,直接爬取代理公司产品数据

1.设计数据库

from django.db import models
from uuslug import slugify
import uuid
import os


def products_directory_path(instance, filename):
  ext = filename.split('.')[-1]
  filename = '{}.{}'.format(uuid.uuid4().hex[:8], ext)
  # return the whole path to the file
  return os.path.join('images', "products", instance.title, filename)


def product_relatedimage_directory_path(instance, filename):
  ext = filename.split('.')[-1]
  filename = '{}.{}'.format(uuid.uuid4().hex[:8], ext)
  # return the whole path to the file
  return os.path.join('images', "product_relatedimage", instance.product.title, filename)


class ProductsCategory(models.Model):
  """产品分类"""
  name = models.CharField('产品分类名', max_length=80, unique=True)
  description = models.TextField('产品分类描述', blank=True, null=True)
  slug = models.SlugField('slug', max_length=80, blank=True, null=True)
  parent_category = models.ForeignKey('self', verbose_name="父级分类", blank=True, null=True, on_delete=models.CASCADE)

  def save(self, *args, **kwargs):
    if not self.id or not self.slug:
      self.slug = slugify(self.name)
    super().save(*args, **kwargs)

  def __str__(self):
    return self.name

  class Meta:
    ordering = ['name']
    verbose_name = "产品分类"
    verbose_name_plural = verbose_name


class ProductsTag(models.Model):
  """产品标签"""
  name = models.CharField('产品标签名', max_length=30, unique=True)
  slug = models.SlugField('slug', max_length=40)

  def __str__(self):
    return self.name

  def save(self, *args, **kwargs):
    if not self.id or not self.slug:
      self.slug = slugify(self.name)
    super().save(*args, **kwargs)

  class Meta:
    ordering = ['name']
    verbose_name = "产品标签"
    verbose_name_plural = verbose_name


class Product(models.Model):
  title = models.CharField('标题', max_length=255, unique=True)
  slug = models.SlugField('slug', max_length=255, blank=True, null=True)
  jscs = models.TextField('技术参数', blank=True, null=True)
  image = models.ImageField(upload_to=products_directory_path, verbose_name="产品图片")
  views = models.PositiveIntegerField('浏览量', default=0)
  category = models.ForeignKey('ProductsCategory', verbose_name='分类', on_delete=models.CASCADE, blank=True, null=True)
  tags = models.ManyToManyField('ProductsTag', verbose_name='标签集合', blank=True)

  def save(self, *args, **kwargs):
    if not self.id or not self.slug:
      self.slug = slugify(self.title)
    super().save(*args, **kwargs)

  def update_views(self):
    self.views += 1
    self.save(update_fields=['views'])

  def get_pre(self):
    return Product.objects.filter(id__lt=self.id).order_by('-id').first()

  def get_next(self):
    return Product.objects.filter(id__gt=self.id).order_by('id').first()

  def __str__(self):
    return self.title

  class Meta:
    verbose_name = "产品"
    verbose_name_plural = verbose_name


class ProductAdvantage(models.Model):
  content = models.TextField('产品优势', blank=True, null=True)
  product = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True)

  def __str__(self):
    return self.content

  class Meta:
    verbose_name = "产品优势"
    verbose_name_plural = verbose_name


class ProductBody(models.Model):
  body = models.CharField('产品内容', max_length=256, blank=True, null=True)
  product = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True)

  def __str__(self):
    return self.product.title

  class Meta:
    verbose_name = "产品内容"
    verbose_name_plural = verbose_name

2.脚本编写

2.1编写获取网页源代码函数

def get_one_page(url):
  try:
    headers = {
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"}
    res = requests.get(url=url, headers=headers)
    res.encoding = 'utf-8'
    if res.status_code == 200:
      return res.text
    else:
      return None
  except Exception:
    return None

2.2根据base页面获取所有产品分类页面链接

if __name__ == '__main__':
  content = get_one_page(url)
  tree = etree.HTML(content)
  # 产品分类url
  catgory_urls = tree.xpath('//div[@class="fdh-01-nav"]/div/h3/a/@href')
  # 处理catgory_urls
  for url in catgory_urls:
    url = 'http://www.kexinjianji.com' + url
    print(url)

2.3根据产品分类页面链接获取对应所有产品链接

if __name__ == '__main__':
  content = get_one_page(url)
  tree = etree.HTML(content)
  # 产品分类
  catgory = tree.xpath('//div[@class="cplb-3n-ts-03 b"]/h3/span/text()')
  print("产品分类:" + catgory[0])
  # 该分类下产品url
  urls = tree.xpath('//div[@class="cplb-3n-ts-03-list"]/dl/dt/a/@href')
  # 处理url
  for url in urls:
    url = 'http://www.kexinjianji.com' + url
    print(url)
  print("=====================================================")

两者结合起来就可以打印出所有产品链接

if __name__ == '__main__':
  content = get_one_page(url)
  tree = etree.HTML(content)
  # 产品分类url
  catgory_urls = tree.xpath('//div[@class="fdh-01-nav"]/div/h3/a/@href')
  # 处理catgory_urls
  for url in catgory_urls:
    url = 'http://www.kexinjianji.com' + url
    content = get_one_page(url)
    tree = etree.HTML(content)
    # 产品分类
    catgory = tree.xpath('//div[@class="cplb-3n-ts-03 b"]/h3/span/text()')
    print("产品分类:" + catgory[0])
    # 该分类下产品url
    urls = tree.xpath('//div[@class="cplb-3n-ts-03-list"]/dl/dt/a/@href')
    # 处理url
    for url in urls:
      url = 'http://www.kexinjianji.com' + url
      print(url)
    print("=====================================================")

2.2使用xpath解析函数返回产品链接的内容

if __name__ == '__main__':
  content = get_one_page(url)
  tree = etree.HTML(content)
  # 产品名称
  title = tree.xpath('//*[@id="wrap"]//h1/text()')
  images = tree.xpath('//div[@class="sol_tj_left"]/a/img/@src')
  # 产品图片
  images_url = 'http://www.kexinjianji.com/' + images[0]
  # 性能特点
  xntd = tree.xpath('//div[@class="w"]//div/span/text()|//div[@class="w"]//div/text()')
  # 技术参数
  jscs = tree.xpath('//table')[0]
  jscs_str = etree.tostring(jscs, encoding='utf-8').decode('utf-8')
  # 产品内容
  cpnr = tree.xpath('//div[@class="describe"]/p')
  print('产品名称:' + title[0])
  print('产品图片:' + images_url)
  for td in xntd:
    print('性能特点:' + td)
  print('技术参数:' + jscs_str)
  for cp in cpnr:
    # string(.) 获取当前标签下所有文本内容
    cp = cp.xpath('string(.)')
    print('产品内容:' + cp)
  print('============================================')

将三者结合在一起就可以获取所有产品信息

if __name__ == '__main__':
  content = get_one_page(url)
  tree = etree.HTML(content)
  # 产品分类url
  catgory_urls = tree.xpath('//div[@class="fdh-01-nav"]/div/h3/a/@href')
  # 处理catgory_urls
  for url in catgory_urls:
    url = 'http://www.kexinjianji.com' + url
    content = get_one_page(url)
    tree = etree.HTML(content)
    # 产品分类
    catgory = tree.xpath('//div[@class="cplb-3n-ts-03 b"]/h3/span/text()')
    # 该分类下产品url
    urls = tree.xpath('//div[@class="cplb-3n-ts-03-list"]/dl/dt/a/@href')
    # 处理url
    for url in urls:
      url = 'http://www.kexinjianji.com' + url
      content = get_one_page(url)
      try:
        tree = etree.HTML(content)
        # 产品名称
        title = tree.xpath('//*[@id="wrap"]//h1/text()')
        images = tree.xpath('//div[@class="sol_tj_left"]/a/img/@src')
        # 产品图片
        images_url = 'http://www.kexinjianji.com' + images[0]
        # 性能特点
        xntd = tree.xpath('//div[@class="w"]//div/span/text()|//div[@class="w"]//div/text()')
        # 技术参数
        jscs = tree.xpath('//table')[0]
        jscs_str = etree.tostring(jscs, encoding='utf-8').decode('utf-8')
        # 产品内容
        cpnr = tree.xpath('//div[@class="describe"]/p')
        print("产品分类:" + catgory[0])
        print('产品链接:' + url)
        print('产品名称:' + title[0])
        print('产品图片:' + images_url)
        for td in xntd:
          print('性能特点:' + td.strip())
        # print('技术参数:' + jscs_str)
        for cp in cpnr:
          # string(.) 获取当前标签下所有文本内容
          cp = cp.xpath('string(.)')
          print('产品内容:' + cp)
        print('============================================')
      except Exception as e:
        print(e)
        print('出错url:' + url)
        pass

3.存储到django模型

import requests
from lxml.html import etree
import os
import django
import uuid
from django.core.files.base import ContentFile

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jiaobanzhan.settings")
django.setup()

from products.models import ProductBody, ProductsCategory, Product, ProductAdvantage

url = 'http://www.kexinjianji.com/product/hzshntjbz_1/'


def get_one_page(url):
  try:
    headers = {
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"}
    res = requests.get(url=url, headers=headers, timeout=10)
    res.encoding = 'utf-8'
    if res.status_code == 200:
      return res.text
    else:
      return None
  except Exception:
    print('aa')
    return None


if __name__ == '__main__':
  content = get_one_page(url)
  tree = etree.HTML(content)
  # 产品分类url
  catgory_urls = tree.xpath('//div[@class="fdh-01-nav"]/div/h3/a/@href')
  # 处理catgory_urls
  for url in catgory_urls:
    url = 'http://www.kexinjianji.com' + url
    content = get_one_page(url)
    tree = etree.HTML(content)
    # 产品分类
    p_catgory = tree.xpath('//div[@class="cplb-3n-ts-03 b"]/h3/span/text()')
    # 该分类下产品url
    urls = tree.xpath('//div[@class="cplb-3n-ts-03-list"]/dl/dt/a/@href')
    # 处理url
    for url in urls:
      url = 'http://www.kexinjianji.com' + url
      content = get_one_page(url)
      try:
        tree = etree.HTML(content)
        # 产品名称
        title = tree.xpath('//*[@id="wrap"]//h1/text()')
        images = tree.xpath('//div[@class="sol_tj_left"]/a/img/@src')
        # 产品图片
        images_url = 'http://www.kexinjianji.com' + images[0]
        # 性能特点
        xntd = tree.xpath('//div[@class="w"]//div/span/text()|//div[@class="w"]//div/text()')
        # 技术参数
        jscs = tree.xpath('//table')[0]
        jscs_str = etree.tostring(jscs, encoding='utf-8').decode('utf-8')
        # 产品内容
        cpnr = tree.xpath('//div[@class="describe"]/p')
        # 判断是否有这分类,没有则新建
        catgory = p_catgory[0]
        products_catgory = ProductsCategory.objects.filter(name=catgory).exists()
        if products_catgory:
          products_catgory = ProductsCategory.objects.get(name=catgory)
        else:
          products_catgory = ProductsCategory(name=catgory)
          products_catgory.save()
        print(products_catgory)

        # 保存产品图片
        image_content = requests.get(url=images_url)
        ext = images_url.split('.')[-1] # 获取图片类型
        filename = '{}.{}'.format(uuid.uuid4().hex[:8], ext) # 随机生成图片名字
        upload_image_file = ContentFile(image_content.content, name=filename) # 将图片保存为django类型
        product = Product(title=title[0], jscs=jscs_str, image=upload_image_file, category=products_catgory)
        product.save()
        for td in xntd:
          product_advantage = ProductAdvantage()
          product_advantage.content = td
          product_advantage.product = product
          product_advantage.save()
        for cp in cpnr:
          cp = cp.xpath('string(.)')
          product_body = ProductBody()
          product_body.body = cp
          product_body.product = product
          product_body.save()
      except Exception as e:
        print(e)
        print('出错url:' + url)

最后自己手动处理出错url(页面没有获取到技术参数,技术参数是一张图片)

4.总结

1.xpath 获取标签内容时,p标签中嵌套span标签,源码如下

<div class="describe" style="position: relative;"> 
   <p><span>板  宽:</span>1500mm</p> 
   <p><span>板  厚:</span>4.5 mm</p> 
   <p><span>出料口:</span>6口</p> 
   <p><span>重  量:</span>6000 kg</p>
</div>

使用xpath获取p标签内容
我想得到的效果如下
板 宽:1500mm
板 厚:4.5 mm
出料口:6口
重 量:6000 kg
使用以下xpath 只能分开获取,不是想要的效果

//div[@class="describe"]/p/span/text()|//div[@class="describe"]/p/text()

百度之后找到的解决办法,使用xpath(‘string(.)')
1.先获取所有p标签

cpnr = tree.xpath('//div[@class="describe"]/p')

2.使用**string(.)**获取所有标签所有文本

cp = cp.xpath('string(.)')

循环遍历所有p标签即可

到此这篇关于python利用xpath爬取网上数据并存储到django模型中的文章就介绍到这了,更多相关xpath爬取网上数据存储到django模型内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
通过C++学习Python
Jan 20 Python
在Python的框架中为MySQL实现restful接口的教程
Apr 08 Python
Python中在for循环中嵌套使用if和else语句的技巧
Jun 20 Python
python常用函数详解
Sep 13 Python
python删除服务器文件代码示例
Feb 09 Python
Python3.7实现中控考勤机自动连接
Aug 28 Python
Python实现Restful API的例子
Aug 31 Python
python线程信号量semaphore使用解析
Nov 30 Python
Pytorch实现神经网络的分类方式
Jan 08 Python
python numpy--数组的组合和分割实例
Feb 24 Python
Python模块zipfile原理及使用方法详解
Aug 04 Python
python基础学习之生成器与文件系统知识总结
May 25 Python
用python 绘制茎叶图和复合饼图
Feb 26 #Python
python lambda的使用详解
Feb 26 #Python
python爬虫scrapy框架之增量式爬虫的示例代码
Feb 26 #Python
详解Python openpyxl库的基本应用
Feb 26 #Python
解决python的空格和tab混淆而报错的问题
Feb 26 #Python
Python Spyder 调出缩进对齐线的操作
Feb 26 #Python
使用Python制作一盏 3D 花灯喜迎元宵佳节
Feb 26 #Python
You might like
DC宇宙的第一个英雄,堪称动漫史鼻祖,如今成为美国文化的象征
2020/04/09 欧美动漫
PHP生成月历代码
2007/06/14 PHP
PHPWind与Discuz截取字符函数substrs与cutstr性能比较
2011/12/05 PHP
php常用经典函数集锦【数组、字符串、栈、队列、排序等】
2019/08/23 PHP
PHP使用递归按层级查找数据的方法
2019/11/10 PHP
div当滚动到页面顶部的时候固定在顶部实例代码
2013/05/27 Javascript
js实现数组去重、判断数组以及对象中的内容是否相同
2013/11/29 Javascript
jQuery中clone()方法用法实例
2015/01/16 Javascript
js实现YouKu的漂亮搜索框效果
2015/08/19 Javascript
jQuery实现可以控制图片旋转角度效果(附demo源码下载)
2016/01/27 Javascript
Kendo Grid editing 自定义验证报错提示的解决方法
2016/11/18 Javascript
浅析Jquery操作select
2016/12/13 Javascript
JS实现密码框的显示密码和隐藏密码功能示例
2016/12/26 Javascript
JavaScript自动点击链接 防止绕过浏览器访问的方法
2017/01/19 Javascript
JavaScript获取当前时间向前推三个月的方法示例
2017/02/04 Javascript
vue axios 给生产环境和发布环境配置不同的接口地址(推荐)
2018/05/08 Javascript
详解jQuery中的easyui
2018/09/02 jQuery
浅谈在vue中使用mint-ui swipe遇到的问题
2018/09/27 Javascript
基于vue-cli搭建多模块且各模块独立打包的项目
2019/06/12 Javascript
浅谈Vue.use到底是什么鬼
2020/01/21 Javascript
[01:35]2018完美盛典章节片——共竞
2018/12/17 DOTA
python操作xml文件详细介绍
2014/06/09 Python
python RabbitMQ 使用详细介绍(小结)
2018/11/08 Python
python子线程退出及线程退出控制的代码
2019/10/16 Python
使用python实现哈希表、字典、集合操作
2019/12/22 Python
基于python-pptx库中文文档及使用详解
2020/02/14 Python
python有序查找算法 二分法实例解析
2020/02/18 Python
Python求凸包及多边形面积教程
2020/04/12 Python
Python self用法详解
2020/11/28 Python
HTML 5.1来了 9月份正式发布 更新内容预览
2016/04/26 HTML / CSS
英国网上购买肉类网站:Great British Meat
2018/10/17 全球购物
科颜氏香港官方网店:Kiehl’s香港
2021/03/07 全球购物
毕业生文员求职信
2013/11/03 职场文书
不服劳动仲裁起诉书
2015/05/20 职场文书
redis实现共同好友的思路详解
2021/05/26 Redis
js作用域及作用域链工作引擎
2022/07/07 Javascript