• 京东全网爬虫


    github_addr:https://github.com/Norni/spider_project/tree/master/jingdong_spider

    1、京东全网爬虫需求

    1.1 目标

    • 明确要抓取的信息

    1.2 目标分解

    1.2.1 抓取首页的分类信息
    • 抓取数据:各级分类的名称URL

      • 大分类名称和url

      • 中分类名称和url

      • 小分类名称和url

    1.2.2 抓取商品信息
    • 抓取数据

      • 商品名称

      • 商品价格

      • 商品评论数量

      • 商品店铺

      • 商品促销

      • 商品版本

      • 商品图片的ULR

    2、开发环境与技术选择

    • 平台:window+Linux

    • 开发语言:python3

    • 开发工具:pycharm

    • 技术选择:

      • 属于全网爬虫,抓取的页面非常多,考虑到效率,使用scrapy+scrapy_redis

      • 数据量很多,选择MongoDB

    3、京东全网爬虫实现步骤

    • 广度优先策略,将类别和商品信息的抓取分开

      • 优点:逐步实现,高稳定性

    3.1 总体设计

    3.2 实现步骤
    • 1.创建爬虫项目

    • 2.根据需求,定义数据模型

    • 3.实现分类爬虫

    • 4.保存分类信息

    • 5.实现商品爬虫

    • 6.保存商品信息

    • 7.实现随机User-Agent和代理IP下载器中间,解决IP反爬

    4、数据模型

    4.1 类别数据模型
    • 类别数据模型类(Category(scrapy.Item)):用于存储类别信息字段

      • b_cate

        • b_cate_name:大类别名称

        • b_cate_url:大类别url

      • m_cate

        • m_cate_name:中类别名称

        • m_cate_url:中类别url

      • s_cate

        • s_cate_name:小类别名称

        • s_cate_url:小类别url

    • 代码

      class Category(scrapy.Item):
         b_cate = scrapy.Field()
         m_cate = scrapy.Field()
         s_cate = scrapy.Field()
    4.2 商品数据模型
    • 商品数据模型类(Product(scrapy.Item)):用于存储商品信息字段

      • product_category:商品类别

      • product_sku_id:商品ID

      • product_name:商品名称

      • product_img_url:商品图片url

      • product_options:商品版本

      • product_shop:商品店铺

      • product_comments:商品评论数量

      • product_ad:商品促销信息

      • product_price:商品价格

      • product_book_info:图书信息,作者,出版社

    • 代码:

      class Product(scrapy.Item):
         product_category = scrapy.Field()
         product_sku_id = scrapy.Field()
         product_name = scrapy.Field()
         product_img_url = scrapy.Field()
         product_price = scrapy.Field()
         product_options = scrapy.Field()
         product_shop = scrapy.Field()
         product_comments = scrapy.Field()
         product_ad = scrapy.Field()
         product_book_info = scrapy.Field()

       

    5、分类爬虫

    5.1 确定目标url
    • 目标:确定分类信息的url

    • 步骤:

      • 进入到京东主页

      • 右击检查,全局搜索分类信息,如“超薄电视”

      • 确定分类的url:“https://dc.3.cn/category/get

    • url分析

      • get请求

      • 查询参数:

        • callback: getCategoryCallback

    5.2 创建爬虫
    • 创建爬虫

      • scrapy genspider cate jd.com

    • 指定起始url

      • https://dc.3.cn/category/get

    • 解析数据,交给引擎

      • 编码分析

        • 返回数据编码为‘GBK’

      • url分析

        有三类数据格式

    • 代码

      import scrapy
      import json
      from jingdong.items import Category


      class CateSpider(scrapy.Spider):
         name = 'cate'
         allowed_domains = ['dc.3.cn']
         start_urls = ['https://dc.3.cn/category/get']

         def get_name_and_url(self, cate_info, cate_name, cate_url):
             cate = list()
             if isinstance(cate_info, list):
                 for _ in cate_info:
                     item = dict()
                     item[cate_name] = _.split(r'|')[1]
                     url = _.split(r'|')[0]
                     if 'jd.com' in url:
                         item[cate_url] = "https://" + url
                     elif url.count("-") == 1:
                         item[cate_url] = 'https://channel.jd.com/{}.html'.format(url)
                     elif url.count("-") == 2:
                         item[cate_url] = 'https://list.jd.com/list.html?cat={}'.format(url.replace('-', ','))
                     cate.append(item)
                 return cate
             if isinstance(cate_info, str):
                 item = dict()
                 item[cate_name] = cate_info.split(r'|')[1]
                 url = cate_info.split(r'|')[0]
                 if 'jd.com' in url:
                     item[cate_url] = "https://" + url
                 elif url.count("-") == 1:
                     item[cate_url] = 'https://channel.jd.com/{}.html'.format(url)
                 elif url.count("-") == 2:
                     item[cate_url] = 'https://list.jd.com/list.html?cat={}'.format(url.replace('-', ','))
                 cate.append(item)
                 return cate

         def get_info_from_s(self, data):
             n_cate_list = list()
             s_cate_list = list()
             if isinstance(data, list):
                 for _ in data:
                     # 获取单个条目下的数据
                     name = _['n']
                     info = _["s"]
                     if name:
                         n_cate_list.append(name)
                     if info:
                         s_cate_list.append(info)
                 return n_cate_list, s_cate_list
             if isinstance(data, dict):
                 name = data['n']
                 info = data["s"]
                 if name:
                     n_cate_list.append(name)
                 if info:
                     s_cate_list.append(info)
                 return n_cate_list, s_cate_list

         def parse(self, response):
             result = json.loads(response.body.decode("GBK"))
             data_list = result.get('data')
             for data in data_list:
                 # 获取单个大分类
                 category_info = Category()
                 # 获取包含分类的数据
                 s_data = data['s']
                 b_n_cate_list, b_s_cate_list = self.get_info_from_s(s_data)
                 category_info["b_cate"] = self.get_name_and_url(b_n_cate_list, "b_name", "b_url")  # 获取到大分类信息
                 for m_ in b_s_cate_list:
                     for m__ in m_:
                         m_n_cate_str = m__["n"]
                         category_info["m_cate"] = self.get_name_and_url(m_n_cate_str, "m_name", "m_url")  # 获取到中分类信息
                         m_s_cate_list = m__['s']
                         for s_ in m_s_cate_list:
                             s_n_cate_str = s_['n']
                             category_info["s_cate"] = self.get_name_and_url(s_n_cate_str, 's_name', 's_url')
                             yield category_info

       

    6、保存分类数据

    • 目标:把分类信息保存到MongoDB中

    • 步骤:

      • 实现保存分类的CategoryPipeline

      • settings.py中开启

    6.1 实现保存分类的Pipeline类
    • 步骤:

      • open_spider方法中,链接MongoDB数据库,获取要操作的集合

      • close_spider方法中,关闭MongoDB数据库

      • process_item方法中,向MongoDB插入数据

    • 代码

      from pymongo import MongoClient
      from jingdong.settings import MONGO_URL


      class CategoryPipeline(object):
         def open_spider(self, spider):
             if spider.name == 'cate':
                 self.mongo_client = MongoClient(MONGO_URL)
                 self.category = self.mongo_client['jingdong']["category"]

         def close_spider(self, spider):
             if spider.name == "cate":
                 self.mongo_client.close()

         def process_item(self, item, spider):
             if spider.name == 'cate':
                 self.category.insert_one(dict(item))
                 return item
    6.2 在settings.py中开启
    ITEM_PIPELINES = {
      'jingdong.pipelines.CategoryPipeline': 300,
    }

    7、商品爬虫

    • 把MongoDB中存储的分类信息,放到redis_key中指定的列表中

    • 支持分布式爬虫,当然也可以在一台电脑上运行多次,以启动多个进程,充分利用CPU的多核

     

    7.1 方案一
    • 起始url为search入口,即该网页输入框API

    • 构造下页url

    • 此方案直接从XML中获取数据,用re或xpath提取,过于繁琐,但是能够拿到详情页数据,包括商品名称及商品URL,商品价格,商品图片URL,店铺及店铺URL

    • 缺点

      • 可能未兼容所有的商品,比如兼容手机,其他普通商品,但是书籍需要的信息不全面

    • spider代码

      import scrapy
      import re
      from pprint import pprint


      class ProductSpider(scrapy.Spider):
         name = 'product'
         allowed_domains = ['jd.com']
         start_urls = ['https://search.jd.com/Search?keyword=%E6%B8%B8%E6%88%8F%E6%89%8B%E6%9C%BA&qrst=1&stock=1&page=1']

         def parse(self, response):
             html_str = response.body.decode()
             page_info = dict()
             # 获取页面总数
             page_count = re.compile(r'page_count:"(.*?)"', re.S).findall(html_str)
             page_info["page_count"] = int(page_count[0]) if page_count else None
             # 获取页面当页数
             page_current = re.compile(r'page:"(.*?)",page_count', re.S).findall(html_str)
             page_info["page_current"] = int(page_current[0]) if page_count else None
             # 获取所有的产品信息
             page_info["product_list"] = list()
             product_info_list = re.compile(r'class="p-img"(.*?)class="p-icons"', re.S).findall(html_str)
             ## 获取单个产品的信息
             for one_product_info in product_info_list:
                 info = dict()
                 # 获取标题及链接
                 str_ = re.compile(r'p-name p-name-type-2(.*?)</div>', re.S).findall(one_product_info)[0]
                 title = re.compile(r'em>(.*?)</em>', re.S).findall(str_)
                 info["title"] = re.sub(r' | |s|(<.*?>)', '', title[0]).strip() if title else None
                 href = re.compile(r'href="(.*?)"', re.S).findall(str_)
                 info["href"] = "https:" + href[0] if href else None
                 # 获取价格
                 str_ = re.compile(r'class="p-price"(.*?)</div>', re.S).findall(one_product_info)[0]
                 price = re.compile(r'i>(.*?)</i>', re.S).findall(str_)
                 info["price"] = price[0] if price else None
                 # 获取图片
                 info["pic_info"] = list()
                 img_list = re.compile(r'class="ps-item">(.*?)</li>', re.S).findall(one_product_info)
                 if img_list:
                     for img in img_list:
                         pic_info_ = dict()
                         pic_title = re.compile(r'title="(.*?)">', re.S).findall(img)
                         pic_info_["pic_title"] = pic_title[0] if pic_title else None
                         pic_href = re.compile(r'data-lazy-img="(.*?)"', re.S).findall(img)
                         pic_info_["pic_href"] = "https:" + pic_href[0] if pic_href else "---"
                         info["pic_info"].append(pic_info_)
                 else:
                     pic_url = re.compile(r'data-img="1" src="(.*?)" data-lazy-img', re.S).findall(one_product_info)
                     img_url = "https:" + pic_url[0] if pic_url else "---"
                     info['pic_info'].append(img_url)
                 # 获取评价连接
                 info["comment_href"] = info["href"] + "#comment"
                 # 获取售卖店铺及链接
                 info["store"] = dict()
                 str_ = re.compile(r'class="p-shop"(.*?)</div>', re.S).findall(one_product_info)[0]
                 shop_name = re.compile(r'title="(.*?)"', re.S).findall(str_)
                 info["store"]["shop_name"] = shop_name[0] if shop_name else None
                 shop_href = re.compile(r'href="(.*?)"', re.S).findall(str_)
                 info["store"]["shop_href"] = "https:" + shop_href[0] if shop_href else None
                 # 将单个产品添加到产品列表
                 page_info["product_list"].append(info)
             pprint(page_info)
             next_page = "page={}".format(int(page_info["page_current"])+1)
             keyword = re.findall(r'keyword=(.*?)&', response.url, re.S)[0]
             url_ = "https://search.jd.com/s_new.php?keyword={}&s=30&page=1".format(keyword)
             next_url = url_.split('page=')[0] + next_page
             if page_info['page_current']:
                 while int(page_info['page_current']) <= int(page_info['page_count']):
                     yield scrapy.Request(
                         url=next_url,
                         callback=self.parse
                    )
    • 数据展示

      image-20200707102252934

    7.2 方案2
    • 起始url为search入口,即该网页输入框API

    • 构造下页url

    • 解析html时,只拿商品skuid

    • 通过手机app抓app包,用商品skuid获取商品json数据

      • https://cdnware.m.jd.com/c1/skuDetail/apple/7.3.0/32426231880.json

        • m.jd.com/c1中是c+阿拉伯数值的1

    • PC端获取促销信息

      • 在商品详情页找到促销URL

        • 通过不同的商品界面(有促销,无促销),通过search_all找到关键url

        • url:https://cd.jd.com/promotion/v2?skuId=30888651734&area=17_2980_23644_0&cat=670%2C729%2C4837

      • 分析参数

        • skuid

        • area 固定

        • cat=类别(从app端,返回的json数据获取)

    • PC端获取,确定评论信息的URL

      • url:

        • https://club.jd.com/comment/productPageComments.action?&productId=12882834&score=0&sortType=5&page=0&pageSize=10

      • 参数

        • productId: 11941094

        • score: 0 固定值必须

        • sortType: 5 固定值必须

        • page: 1 当前页数

        • pageSize: 10 固定值,每次返回的数据条数

      • 注意page从0到99,数据中关键字maxPage: 100为总页数

      • 后期,可通过这个api与product_sku_id结合,单独来爬取评论信息

      • 另一个url

        • https://club.jd.com/comment/productCommentSummaries.action?referenceIds=100010816812

        • 参数

          • referenceIds即为商品IP

        • 获取数据

          • 全部评价:CommentCount

          • 默认好评:DefaultGoodCount

          • 好评:GooDCount

          • 中评:GeneralCount

          • 差评:PoorCount

          • 好评度:GoodRate

    • PC端获取,确定商品价格信息的URL

      • url:https://p.3.cn/prices/mgets?&skuIds=J_30888651734

      • 价格在关键字中,包含现价和原价,打折信息

      • 参数:

        • productid:30888651734 商品ID

    7.2.1 实现爬虫
    • 通过search这个api入口发送请求

      • 通过xpath得到sku_id

      • 构造下页请求

    • 手机app抓包

      • 通过charles抓包,得到url

        • https://cdnware.m.jd.com/c1/skuDetail/apple/7.3.0/32426231880.json

        • get请求

        • 返回json数据

        • 参数

          • 商品的sku_id= 32426231880

    • 通过sku_id,构造请求

      • 注意:传递参数时,因为有for循环,如果不深拷贝的话,最后一个对象的product_sku_id会覆盖所有的对象,导致后面拿不到数据

    • 解析通过sku_id拿到的json数据,拿到:

      • product_name:商品名称

        • product[“product_name”]=data[‘wareInfo’][‘basicInfo’][‘name’]

      • product_img_url:商品图片url

        • product[‘product_img_url’] = data[‘wareInfo’][‘basicInfo’][‘wareImage’]

      • product_book_info:图书信息,作者,出版社

        • product[‘product_img_url’] = data[‘wareInfo’][‘basicInfo’][‘bookInfo’]

      • product_options:商品选项

        color_size= = jsonpath(data, '$..colorSize')
        if color_size:
           for s_ in color_size[0]:
               title = s_['title']
               buttons = jsonpath(s_,"$..text")
               product_options['title']=buttons
               

         

      • product_shop:商品店铺

        shop = jsonpath.jsonpath(data, '$..shop')
        if shop:
           shop = shop[0]
           shopinfo = dict()
           if shop:
               shopinfo['shopId'] = shop['shopId']
               shopinfo['shopName'] = shop['name']
               shopinfo['shopScore'] = shop['score']
            else:
               shopinfo['shopName'] = "京东自营"
        product["product_shop"] = shopinfo
               
           

         

      • product_category_id:商品类别ID

        product_category_id = data['wareInfo']['basicInfo']['category']
    • 获取促销信息

      • url : https://cd.jd.com/promotion/v2?skuId=30888651734&area=17_2980_23644_0&cat=670%2C729%2C4837

        • skuId为商品ip

        • area为固定值

        • cat为通过skuid获取到的类别id

        data['ads']
    • 获取价格信息

      • url : https://p.3.cn/prices/mgets?&skuIds=J_30888651734

      • 参数:

        • skuIds为商品ID

      • 注意

        • 价格的域名为p.3.cn,一定要添加到allowed_domains中,否则爬虫会自动过滤掉,导致拿不到价格数据

    • 获取评价

      • url: https://club.jd.com/comment/productPageComments.action?&productId=12882834&score=0&sortType=5&page=0&pageSize=10

    • 最终效果

    • 源码

      import scrapy
      from urllib import parse
      from jingdong.items import ProductItem
      import re
      import json
      import jsonpath
      from copy import deepcopy
      from pprint import pprint


      class Product1Spider(scrapy.Spider):
         name = 'product_1'
         allowed_domains = ['jd.com', 'p.3.cn']

         # start_urls = ['https://search.jd.com/Search?keyword=%E6%B8%B8%E6%88%8F%E6%89%8B%E6%9C%BA']

         def start_requests(self):
             category = {
                 'b_cate':
                    [
                        {'b_name': '美妆', 'b_url': 'https://beauty.jd.com/'},
                        {'b_name': '个护清洁', 'b_url': 'https://channel.jd.com/beauty.html'},
                        {'b_name': '宠物', 'b_url': 'https://channel.jd.com/pet.html'}],
                 'm_cate':
                    [
                        {'m_name': '面部护肤', 'm_url': 'https://channel.jd.com/1316-1381.html'}],
                 's_cate':
                    [
                        {'s_name': '精华', 's_url': 'https://list.jd.com/list.html?cat=1316,1381,13546'}]}
             yield scrapy.Request(
                 url="https://search.jd.com/Search?keyword={}".format(parse.quote(category["s_cate"][0]['s_name'])),
                 callback=self.parse,
                 meta={"item": category}
            )

         def parse(self, response):
             product_category = response.meta['item']
             product = ProductItem()
             product['product_category'] = product_category
             html_str = response.body.decode()
             li_list = response.xpath('//div[contains(@id,"J_goodsList")]/ul/li')
             for li in li_list:
                 sku_id = li.xpath('./@data-sku').extract_first()
                 product['product_sku_id'] = sku_id
                 product['product_detail_url'] = "https://item.jd.com/{}.html".format(sku_id)
                 # 获取店铺信息,类别信息,版本,图片等
                 request_url = "https://cdnware.m.jd.com/c1/skuDetail/apple/7.3.0/{}.json".format(sku_id)
                 yield scrapy.Request(
                     url=request_url,
                     meta={"item": deepcopy(product)},
                     callback=self.parse_skuid_content
                )
             # 构造下页请求
             base_url = "https://search.jd.com/s_new.php?keyword={}&s=30&page=1"
             page_count = re.compile(r'page_count:"(.*?)"', re.S).findall(html_str)
             page_count = int(page_count[0]) if page_count else None
             page_current = re.compile(r'page:"(.*?)",page_count', re.S).findall(html_str)
             page_current = int(page_current[0]) if page_current else None
             next_page = "page={}".format(page_current + 1)
             keyword = parse.quote(product['product_category']['s_cate'][0]["s_name"])
             url_ = "https://search.jd.com/s_new.php?keyword={}&s=30&page=1".format(keyword)
             next_url = url_.split('page=')[0] + next_page
             if page_current and page_count:
                 while page_current <= page_count:
                     yield scrapy.Request(
                         url=next_url,
                         meta={'item': product['product_category']},
                         callback=self.parse
                    )

         def parse_skuid_content(self, response):
             product = response.meta['item']
             data = json.loads(response.text)
             if 'wareInfo' in data:
                 product['product_name'] = data['wareInfo']['basicInfo']['name']
                 # data['wareInfo']['basicInfo']['wareImage']
                 product['product_img_url'] = jsonpath.jsonpath(data, '$..wareImage..big')
                 product['product_book_info'] = data['wareInfo']['basicInfo']['bookInfo']
                 color_size = jsonpath.jsonpath(data, "$..colorSize")
                 product_options = dict()
                 if color_size:
                     for s_ in color_size[0]:
                         title = s_['title']
                         buttons = jsonpath.jsonpath(s_, '$..text')
                         product_options[title] = buttons
                     product['product_options'] = product_options
                 shop = jsonpath.jsonpath(data, '$..shop')
                 if shop:
                     shop = shop[0]
                     shop_info = dict()
                     if shop:
                         shop_info['shopId'] = shop['shopId']
                         shop_info['shopName'] = shop['name']
                         shop_info['shopScore'] = shop['score']
                     else:
                         shop_info['shopName'] = "京东自营"
                     product['product_shop'] = shop_info
                 product['product_category_id'] = data['wareInfo']['basicInfo']['category'].replace(';', ',')
             # 获取促销信息
             ad_url = "https://cd.jd.com/promotion/v2?skuId={}&area=17_2980_23644_0&cat={}".format(product["product_sku_id"], product['product_category_id'])
             yield scrapy.Request(
                 url=ad_url,
                 meta={"item": product},
                 callback=self.get_ad_info
            )

         def get_ad_info(self, response):
             product = response.meta['item']
             data = json.loads(response.text)
             product["product_ad"] = data["ads"][0]['ad']
             # 获取价格
             price_url = "https://p.3.cn/prices/mgets?&skuIds=J_{}".format(product['product_sku_id'])
             yield scrapy.Request(
                 url=price_url,
                 meta={'item': product},
                 callback=self.get_price_info
            )

         def get_price_info(self, response):
             product = response.meta['item']
             data = response.json()
             price_info = dict()
             price_info['original_price'] = data[0]['m']
             price_info['current_price'] = data[0]['p']
             product['product_price'] = price_info
             # 获取评价
             comment_url = "https://club.jd.com/comment/productCommentSummaries.action?referenceIds={}".format(product['product_sku_id'])
             yield scrapy.Request(
                 url=comment_url,
                 meta={'item': product},
                 callback=self.get_comment_info
            )

         def get_comment_info(self, response):
             product = response.meta['item']
             data = response.json()["CommentsCount"][0]
             comments_info = dict()
             comments_info['customer_comment_first_url'] = "https://club.jd.com/comment/productPageComments.action?&productId={}&score=0&sortType=5&page=0&pageSize=10".format(product['product_sku_id'])
             comments_info['CommentCount'] = data['CommentCount']
             comments_info['DefaultGoodCount'] = data['DefaultGoodCount']
             comments_info['GoodCount'] = data['GoodCount']
             comments_info['GeneralCount'] = data['GeneralCount']
             comments_info['PoorCount'] = data['PoorCount']
             comments_info['GoodRate'] = data["GoodRate"]
             product['product_comments'] = comments_info
             yield product
             # pprint(product)
    7.3 商品爬虫实现分布式
    • 修改爬虫类

      • 继承RedisSpider

        • from scrapy_redis.spiders import RedisSpider

      • 指定redis_key

        • redis_key = 'product_1:category'

      • 把重写start_requests改为重写make_request_from_data

            def make_request_from_data(self, data):
               # 根据redis中读取的数据构建请求
               category = pickle.loads(data)
               yield scrapy.Request(
                   url="https://search.jd.com/Search?keyword={}".format(parse.quote(category["s_cate"][0]['s_name'])),
                   callback=self.parse,
                   meta={"item": category}
              )
    • 在settings.py文件中配置scrapy_redis

      # 配置scrapy_redis
      DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'  # 指定去重类
      SCHEDULER = 'scrapy_redis.scheduler.Scheduler'  # 指定scheduler队列
      SCHEDULER_PERSIST = True   # 队列中内容持久化
      REDIS_URL = 'redis://127.0.0.1:6379/0'   # 指定redis的地址
    • 将MongoDB中保存的分类信息,放入到爬虫redis_key的列表中

      • 在项目文件夹下创建add_category_to_redis.py文件

      • 实现方法add_category_to_redis

        • 链接MongoDB

        • 链接Redis

        • 读取MongoDB中分类信息,剔除_id项后,序列化,然后添加到商品爬虫指定的redis中的redis_key中,redis_key是一个列表

        • 关闭MongoDB

      • 代码

        import sys

        sys.path.append('../')
        import pickle
        from pymongo import MongoClient
        from redis import StrictRedis
        from jingdong.settings import MONGO_URL, REDIS_URL
        from jingdong.spiders.product_1 import Product1Spider


        def add_category_to_redis():
           mongo_client = MongoClient(MONGO_URL)
           redis_client = StrictRedis.from_url(REDIS_URL)
           collection = mongo_client['jingdong']['category']
           cursor = collection.find()
           for cur_ in cursor:
               cur_.pop('_id')
               cur = pickle.dumps(cur_)
               redis_client.lpush(Product1Spider.redis_key, cur)
               break
           mongo_client.close()
           redis_client.close()


        if __name__ == "__main__":
           add_category_to_redis()

         

    8、保存商品信息

    • 写商品Pipeline

      • 代码

      class ProductPipeline(object):
         def open_spider(self, spider):
             if spider.name == 'product_1':
                 self.mongo_client = MongoClient(MONGO_URL)
                 self.category = self.mongo_client['jingdong']["product"]

         def close_spider(self, spider):
             if spider.name == "product_1":
                 self.mongo_client.close()

         def process_item(self, item, spider):
             if spider.name == 'product_1':
                 self.category.insert_one(dict(item))
             return item
    • 在settings中开启

    9、下载器中间件

    • user_agent中间件

      class RandomUserAgent(object):

         def process_request(self, request, spider):
             if request.url.startswith("https://cdnware.m.jd.com"):
                 request.headers['User-Agent'] = 'JD4iPhone/164880 (iPhone; iOS 12.1.2; Scale/2.00)'
             else:
                 request.headers['User-Agent'] = random.choice(USER_AGENTS)

       

    • 代理IP的中间件

      • 在middlewares.py中,实现ProxyMiddleware类

      • 实现process_request方法

        • 从代理池中获取一个随机的代理IP,需要指定代理IP的协议,和访问的域名

        • 设置给request.meta[‘proxy’]

      • 实现process_exception方法

        • 当请求出现异常的时候,代理池哪些IP在本域名下是不可用的

      • 代码

        class ProxyMiddleware(object):

           def process_request(self, request, spider):
               # 通过代理池的api接口,获取满足要求的proxy
               # response = ...
               request.meta['proxy'] = response.content.decode()
               return None

           def process_exception(self, request, exception, spider):
               pass
      • 在settings.py中开启

    10、总结

    • 开启步骤:

      • 执行scrapy crawl cate获取分类信息,并将其存储MongoDB中

      • 执行python cate_category_to_redis.py将分类信息从MongoDB放入redis_key

      • 执行scrapy crawl product_1获取商品信息,并将其存入MongoDB中

    • 效果

  • 相关阅读:
    模拟Spring创建Bean和dom4j读取xml文件(视频学习传智播客Spring2.503)
    三种实例化Bean的方式
    junit4测试用例
    Spring注解方式管理事务以及事务传播行为Propagation(视频笔记23)
    Hibernate注解Annotation
    SSH框架整合(二)
    Oracle命令行中启动服务创建用户,权限,密码丢失
    Spring事务管理
    嚯嚯~~第一篇
    fedora下配置dhcpv6服务器
  • 原文地址:https://www.cnblogs.com/nuochengze/p/13264715.html
Copyright © 2020-2023  润新知