范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

爬虫项目实现京东全网爬虫

  一、需求1.1 抓取首页的分类信息抓取数据: 各级分类的名称 和 URL
  1.2 抓取商品信息抓取: 商品名称, 商品价格, 商品评论数量, 商品店铺, 商品促销, 商品选项, 商品图片的URL
  二、开发环境平台: Mac,可以运行Window和Linux上 开发语言: Python3 开发工具: PyCharm 技术选择: 由于全网爬虫, 抓取页面非常多, 为了提高抓的速度, 选择使用scrapy框架 + scrapy_redis分布式组件 由于京东全网的数据量达到了亿级, 存储又是结构化数据, 数据库, 选择使用MongoDB; 三、京东全网爬虫的实现步骤
  我们采用广度优先策略, 我们把类别和商品信息的抓取分开来做. 好处: 可以提高程序的稳定性 3.1 总体设计
  3.2 实现步骤:1. 创建爬虫项目 2. 根据需求, 定义数据数据模型 3. 实现分类爬虫 4. 保存分类信息 5. 实现商品爬虫 6. 保存商品信息 7. 实现随机User-Agent和代理IP下载器中间件, 解决IP反爬.3.3 创建爬虫项目scrapy startproject mall_spider  四、明确要抓取的数据(定义数据模型)
  爬虫数据模型, 我们只能根据需求, 定义一个大概, 随着对项目实现可能会对数据模型做相应的修改. 4.1 类别数据模型类别数据模型类: 用于存储类别信息(Category) - 字段: b_category_name: 大类别名称 b_category_url: 大类别URL m_category_name: 中分类名称 m_category_url: 中分类URL s_category_name: 小分类名称 s_category_url: 小分类URL 代码 class Category(scrapy.Item):   """商品类别"""   # 大分类名称   b_category_name = scrapy.Field()   # 大分类URL   b_category_url = scrapy.Field()   # 中分类名称   m_category_name = scrapy.Field()   # 中分类URL   m_category_url = scrapy.Field()   # 小分类名称   s_category_name = scrapy.Field()   # 小分类URL   s_category_url = scrapy.Field()4.2 商品数据模型商品数据模型类: 用于存储商品信息(Product) 字段  : product_category: 商品类别 product_sku_id: 商品ID product_name: 商品名称 product_img_url: 商品图片URL product_book_info: 图书信息, 作者,出版社 product_option: 商品选项 product_shop: 商品店铺 product_comments: 商品评论数量 product_ad: 商品促销 product_price: 商品价格 代码  class Product(scrapy.Item):   # 商品类别   product_category = scrapy.Field()   # 商品ID   product_sku_id = scrapy.Field()   # 商品名称   product_name = scrapy.Field()   # 商品图片URL   product_img_url = scrapy.Field()   # 商品店铺   product_shop = scrapy.Field()   # 图书信息, 作者,出版社   product_book_info = scrapy.Field()   # 商品选项   product_option = scrapy.Field()   # 商品评论数量   product_comments = scrapy.Field()   # 商品促销   product_ad = scrapy.Field()   # 商品价格   product_price = scrapy.Field()五、商品分类查询5.1 分析, 分类信息的URL目标  :  确定分类信息的URL  步骤  : 进入到京东首页 右键检查, 打开开发者工具, 搜索  家用电器  确定分类的URL 图解  :
  结论  : - 分类URL:  https://dc.3.cn/category/get  5.2 创建爬虫, 抓取数据目标  :  抓取分类数据, 交给引擎  步骤  : 创建类别爬虫 指定起始URL 解析数据, 交给引擎
  5.2.1 创建爬虫 进入项目目录:  cd mall_spider  创建爬虫:  scrapy genspider category_spider jd.com
  5.2.2. 指定起始URL 修改起始URL:  https://dc.3.cn/category/get
  5.2.3. 解析数据, 交给引擎 分析数据格式: 整体数据
  各级分类位置
  分类信息格式 格式1: jiadian.jd.com|家用电器||0  特点: 第一项分类URL,第二项分类名称 格式2: `652-654|摄影摄像||0 对应的URL:  https://channel.jd.com/652-654.html  特点:第一项是频道ID, 包含一个  -  格式3: 1318-2628-12131|户外风衣||0  对应URL:  https://list.jd.com/list.html?cat=1318,2628,12131  特点: 第一项为分类ID, 包含两个  -  代码  实现 # -*- coding: utf-8 -*- import scrapy import json from mall_spider.items import Category  class JdCategorySpider(scrapy.Spider):     name = "jd_category"     allowed_domains = ["dc.3.cn"]     start_urls = ["https://dc.3.cn/category/get"]     # 频道URL模板     channel_url_pattern = "https://channel.jd.com/{}.html"     # 列表URL模板     list_url_pattern = "https://list.jd.com/list.html?cat={}"      def parse(self, response):         # 把传递过来的信息GBK进行解码, 因为京东的类别信息, 是使用GBK, 编码的         categorys  = json.loads(response.body.decode("GBK"))         # 取出"data" 键中分类列表         categorys = categorys["data"]          # 遍历分类列表         for category in categorys:             item = Category()             # 获取大分类,包含子分类; 注: 第一层的分类都在在0索引上;             b_category = category["s"][0]             # 获取大分类信息(分类URL,名称)             b_category_info =  b_category["n"]             # 解析大分类信息, 获取大分类名称和URL             item["b_category_name"], item["b_category_url"] = self.get_category_item(b_category_info)              # 获取中分类列表             m_category_s =  b_category["s"]              # 遍历第二层分类列表             for m_category in m_category_s:                 # 获取中分类信息                 m_category_info = m_category["n"]                 item["m_category_name"], item["m_category_url"] = self.get_category_item(m_category_info)                 # 获取小分类列表                 s_category_s = m_category["s"]                 # 遍历小分类分类列表                 for s_category in s_category_s:                     # 获取第三层分类名称                     s_category_info = s_category["n"]                     # 获取三级分类信息                     item["s_category_name"], item["s_category_url"] = self.get_category_item(s_category_info)                     # print(item["s_category_name"])                     # 把分类信息交给引擎                     yield item      def get_category_item(self, category_info):         # 使用 `|` 分割类型信息字符串         categorys =   category_info.split("|")         # 类别的名称         category_name = categorys[1]         # 类别的URL         category_url = categorys[0]         # 获取 category_url 中 `-` 个数         count = category_url.count("-")          if category_url.count("jd.com") != 0:             # 其他就是本身就是URL, 前面补一个协议头             category_url = "https://" + category_url         elif count == 1:             # 如果包含一个 "-" 是二级分类的频道             category_url = self.channel_url_pattern.format(category_url)         else:             # 如果包含2个 "-" 是三级分类的列表             # 1. 把 `-` 替换为 ","             category_url = category_url.replace("-", ",")             # 2. 生成具体列表的URL             category_url = self.list_url_pattern.format(category_url)         return category_name, category_url六、保存分类数据6.1 实现保存分类的Pipeline类步骤  : open_spider  方法中, 链接MongoDB数据库, 获取要操作的集合 process_item   方法中, 向MongoDB中插入类别数据 close_spider   方法中, 关闭MongoDB的链接 代码  from mall_spider.spiders.jd_category import JdCategorySpider from pymongo import MongoClient  class CategoryPipeline(object):      def open_spider(self, spider):         if isinstance(spider, JdCategorySpider):             # 建立MongoDB数据库链接             self.client = MongoClient(MONGO_URL)             # 获取要操作集合             self.category = self.client["jd"]["category"]      def process_item(self, item, spider):         if isinstance(spider, JdCategorySpider):             # 把数据插入到mongo中             self.category.insert_one(dict(item))         return item      def close_spider(self, spider):         """关闭"""         if isinstance(spider, JdCategorySpider):             self.client.close()6.2 在settings.py开启, 类别的Pipeline# 在settings.py开启, 类别的Pipeline ITEM_PIPELINES = {    "mall_spider.pipelines.CategoryPipeline": 300, }七、实现商品爬虫总体设计  :把MongoDB中存储的分类信息, 放到redis_key指定列表中 支持分布式爬虫, 当然也可以在一台电脑上运行多次, 以启动多个进程,充分使用CPU的多核. 所以这里的爬虫, 先从一个分类开始抓就可以了, 后面再改造为分布式
  目标  : 抓取商品数据 步骤  : 分析, 确定数据所在的URL 代码实现 商品爬虫实现分布式 7.1 分析, 确定数据所在的URL列表页 提取商品 skuid
  实现翻页 获取下一页URL
  没有下一页的情况
  详情页 由于PC和手机页面商品信息, 在js中, 且比较分散, 并且每次请求数量页比较大, 我们这里使用手机抓包, 抓到json数据. 商品基本信息 图:
  URL:  https://cdnware.m.jd.com/c1/skuDetail/apple/7.3.0/32426231880.json  ; 最后一部分是商品skuid 可以获取到的信息: 商品名称, 商品店铺信息 , 商品类别id, 商品品牌id, 商品选项 { "code": "0", "wareInfo": {     "recommendInfo": {         "recommendList": null     },     // 商品店铺信息     "shopInfo": {         "shop": {             "shopId": 1000000127,             "name": "京东Apple产品专营店",             ...         },         "basicInfo": {         "gift": false,         "bookInfo": {             // 如果是书,这里是书的选项信息             "display": false         },          "colorSizeInfo": {             // 商品选项信息列表 有的没有             "colorSize": [{                 "buttons": [{                     "no": "1",                     "skuList": ["100000177738", "100000287117", "100000287145", "100000309448", "100000309450", "100000375233", "100000435832", "100000458753", "100000458755", "100001860767", "100001860773"],                     "text": "金色"                 }, {                     "no": "2",                     "skuList": ["100000177764", "100000287113", "100000287135", "100000435780", "100000435816", "100000435818", "100000569049", "100000602206", "100000602208", "100001860765", "100002539302"],                     "text": "深空灰色"                 }, {                     "no": "3",                     "skuList": ["100000177740", "100000177784", "100000287147", "100000435834", "100000458737", "100000458739", "100000602174", "100000602176", "100000602204", "100001860789", "100002539304"],                     "text": "银色"                 }],                 "title": "颜色"             }, {                 "buttons": [{                     "no": "1",                     "skuList": ["100000177738", "100000177740", "100000177764", "100000177784", "100000287113", "100000287117", "100000287135", "100000287145", "100000287147"],                     "text": "公开版"                 },                 ...                 ],                 "title": "版本"             }, {                 "buttons": [{                     "no": "1",                     "skuList": ["100000177764", "100000287145", "100000287147", "100000375233", "100000435818", "100000458739", "100000458755", "100000602204", "100000602208", "100001860765", "100001860773", "100001860789"],                     "text": "64GB"                 },                  ...                 ],                 "title": "内存"             }],             "colorSizeTips": "#与其他已选项无法组成可售商品,请重选"         },         ...         // 品牌ID         "brandID": "14026",         ...         // 商品图片         "wareImage": [{             "small": "https://m.360buyimg.com/mobilecms/s720x720_jfs/t1/3/15/4536/138660/5b997bf8Ed72ebce7/819dcf182d743897.jpg!q70.jpg.webp",             ...           }           ...         ],         ...         // 商品名称         "name": "Apple iPhone XS Max (A2104) 256GB 深空灰色 移动联通电信4G手机 双卡双待",         // 商品类别id         "category": "9987;653;655"         }     } }
  商品促销信息(PC端): 图:
  URL: https://cd.jd.com/promotion/v2?skuId=4749506&area=1_72_4137_0&cat=737%2C794%2C798 参数 skuId=4749506: 商品sku_id area=1_72_4137_0: 购买者区域, 固定的 cat=737%2C794%2C798: 类别 数据 { ... // 商品促销信息 "ads": [{     "id": "AD_4749506",     "ad": "【即刻预约,21号秒杀到手价2999】 1、前100名晒单送腾讯企鹅影院季卡,联系客服领取!! 2、曲面爆款,5.5万好评推荐!升级55Q1D超清全面屏电视" }], ... }
  商品评论信息(PC端) 图:
  URL: https://club.jd.com/comment/productCommentSummaries.action?referenceIds=4749506 参数 referenceIds=4749506: 商品sku_id 数据 {"CommentsCount":[     {         "CommentCountStr":"10万+",          "CommentCount":100000, //评论数量         "AverageScore":5,         "GoodRate":0.98, //好评率         "PoorCountStr":"600+",          "PoorCount":600, // 差评数量         ...     }]}商品价格信息: 图:
  URL: https://p.3.cn/prices/mgets?skuIds=J_4749506 参数: skuIds=J_4749506 商品的sku_id 数据 [   {       "op": "5499.00",       "m": "5999.00",       "id": "J_4749506", //商品skuid       "p": "3299.00" // 商品价格       }   ]7.2 代码实现步骤: 重写start_requests方法, 根据分类信息构建列表页的请求 解析列表页, 提取商品的skuid, 构建商品基本的信息请求; 实现翻页 解析商品基本信息, 构建商品促销信息的请求 解析促销信息,构建商品评价信息的请求, 解析商品评价信息, 构建价格信息的请求 解析价格信息 代码: # -*- coding: utf-8 -*- import scrapy import json from jsonpath import jsonpath  class JdProductSpider(scrapy.Spider):     name = "jd_product"     allowed_domains = ["jd.com", "p.3.cn"]      def start_requests(self):         category = {  "b_category_name" : "家用电器",                       "b_category_url" : "https://jiadian.jd.com",                       "m_category_name" : "洗衣机",                       "m_category_url" : "https://list.jd.com/list.html?cat=737,794,880",                       "s_category_name" : "洗衣机配件",                       "s_category_url" : "https://list.jd.com/list.html?cat=737,794,877" }          yield scrapy.Request(category["s_category_url"], self.parse, meta={"category": category})      def parse(self, response):         # 获取类别信息         category = response.meta["category"]         # 获取类别的URL         category_url = response.url.split("&")[0]         # 获取所有商品的sku_ids         sku_ids = response.xpath("//p[contains(@class, "j-sku-item")]/@data-sku").extract()         # 遍历sku_ids, 构建基本详情信息的请求         for sku_id in sku_ids:             item = {                  "product_category": category,                  "product_sku_id":sku_id             }             product_url = "https://cdnware.m.jd.com/c1/skuDetail/apple/7.3.0/{}.json".format(sku_id)             yield scrapy.Request(product_url, callback=self.parse_product, meta={"item": item})           # 获取下一页的URL         next_url = response.xpath("//a[@class="pn-next"]/@href").extract_first()         if next_url:             # 补全URL             next_url = response.urljoin(next_url)             # 构建下一页请求             yield scrapy.Request(next_url, callback=self.parse, meta={"category": category})      def parse_product(self, response):         # 取出传递过来的数据         item = response.meta["item"]         # 把响应数据数据转为字典         product_dic = json.loads(response.text)          # 获取商品名称         item["product_name"] = product_dic["wareInfo"]["basicInfo"]["name"]         if  item["product_name"]:             # 获取类别id, 把 `;` 替换为 ,             item["product_category_id"] = product_dic["wareInfo"]["basicInfo"]["category"].replace(";", ",")             # 获取店铺信息             product_shop = jsonpath(product_dic, "$..shop")             if product_shop:                 product_shop = product_shop[0]                 if product_shop is None:                     item["product_shop"] = {"name":"京东自营"}                 else:                     item["product_shop"] = {                         "shopId": product_shop["shopId"],                         "name": product_shop["name"],                         "score": product_shop["score"],                         "url": product_shop["url"],                     }              # 如果是书, 记录书的信息             if product_dic["wareInfo"]["basicInfo"]["bookInfo"]["display"]:                 item["product_book_info"] = product_dic["wareInfo"]["basicInfo"]["bookInfo"]                 # 删除display                 del item["book_info"]["display"]             # 获取商品选购信息             color_sizes = jsonpath(product_dic, "$..colorSize")             product_option = {}             if color_sizes:                 for color_size in color_sizes[0]:                     title = color_size["title"]                     texts = jsonpath(color_size, "$..text")                     product_option.update({title:texts})                     # print(product_option)             item["product_option"] = product_option             # 商品图片             item["product_img_url"] = jsonpath(product_dic, "$..wareImage[0].small")[0]              # 构建促销信息的请求             ad_url = "https://cd.jd.com/promotion/v2?skuId={}&area=1_72_4137_0&cat={}".format(item["product_sku_id"], item["product_category_id"])             yield scrapy.Request(ad_url, callback=self.parse_ad, meta={"item": item})      def parse_ad(self, response):         """获取商品促销"""         item = response.meta["item"]         ad_dic = json.loads(response.body.decode("GB18030"))         ad =  ad_dic["ads"][0]["ad"]         item["product_ad"] = ad          # for key, value in item.items():         #     print("{} = {}".format(key, value))          # 构建平均信息请求         comments_url = "https://club.jd.com/comment/productCommentSummaries.action?referenceIds={}".format(item["product_sku_id"])         yield scrapy.Request(comments_url, callback=self.parse_comments, meta={"item": item})      def parse_comments(self, response):         """解析商品评论信息"""         item = response.meta["item"]         comments_dic = json.loads(response.text)         comments = {             "comment_count": jsonpath(comments_dic, "$..CommentCount")[0],             "good_rate": jsonpath(comments_dic, "$..GoodRate")[0],             "poor_count": jsonpath(comments_dic, "$..PoorCount")[0],         }         item["product_comments"] = comments         # print(item)         # 构建价格请求         price_url = "https://p.3.cn/prices/mgets?skuIds=J_{}".format(item["product_sku_id"])         yield scrapy.Request(price_url, callback=self.parse_price, meta={"item": item})      def parse_price(self, response):         """解析价格"""         item = response.meta["item"]         item["product_price"] = json.loads(response.text)[0]["p"]         # print(item)         yield item7.3 商品爬虫实现分布式步骤  : 修改爬虫类 在settings文件中配置scrapy_redis 写一个程序用于把MongoDB中分类信息, 放入到爬虫redis_key指定的列表中
  1. 修改爬虫类 步骤  : 修改继承关系: 继承RedisSpider 指定redis_key 把重写start_requests 改为 重写 make_request_from_data 代码  from scrapy_redis.spiders import RedisSpider import pickle  #  1. 修改继承关系: 继承RedisSpider class JdProductSpider(RedisSpider):     name = "jd_product"     allowed_domains = ["jd.com", "p.3.cn"]     # 2. 指定redis_key     redis_key = "jd_product:start_category"      # 3. 把重写start_requests 改为 重写 make_request_from_data     def make_request_from_data(self, data):         # 把从Redis中读取到分类信息, 转换为字典         category = pickle.loads(data)         return scrapy.Request(category["s_category_url"], self.parse, meta={"category": category})注意  : 在 make_request_from_data  不能使用  yield   必须使用  return
  2. 在settings文件中配置scrapy_redis # MongoDB数据库的URL MONGO_URL = "mongodb://127.0.0.1:27017"  # REDIS数据链接 REDIS_URL = " redis://127.0.0.1:6379/0"  # 去重容器类: 用于把已爬指纹存储到基于Redis的set集合中 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 调度器: 用于把待爬请求存储到基于Redis的队列 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 是不进行调度持久化: # 如果是True, 当程序结束的时候, 会保留Redis中已爬指纹和待爬的请求 # 如果是False, 当程序结束的时候, 会清空Redis中已爬指纹和待爬的请求 SCHEDULER_PERSIST = True
  3. 写一个程序用于把MongoDB中分类信息, 放入到爬虫redis_key指定的列表中 步骤  : 在项目文件夹下创建  add_category_to_redis.py
  实现方法  add_category_to_redis  : 链接MongoDB 链接Redis 读取MongoDB中分类信息, 序列化后, 添加到商品爬虫redis_key指定的list 关闭MongoDB 在 if __name__ == "__main__":  中调用 add_category_to_redis  方法
  代码  from redis import StrictRedis from pymongo import MongoClient import pickle  from mall_spider.settings import MONGO_URL, REDIS_URL from mall_spider.spiders.jd_product import JdProductSpider  # 把MongoDB中分类信息, 添加到Redis中 def add_category_to_redis():     # 链接MongoDB     client = MongoClient(MONGO_URL)     # 链接Redis     redis = StrictRedis.from_url(REDIS_URL)      cursor = client["jd"]["category"].find()     # 读取MongoDB中分类信息, 序列化后, 添加到商品爬虫redis_key指定的list     for category in cursor:         redis.rpush(JdProductSpider.redis_key, pickle.dumps(category))      # 关闭MongoDB的链接     client.close()  if __name__ == "__main__":     add_category_to_redis()八、保存商品信息8.1 实现存储商品Pipeline类步骤  在 open_spider方法, 建立MongoDB数据库连接, 获取要操作的集合 在 process_item方法, 把数据插入到MongoDB中 在close_spider方法, 关闭数据库连接 代码 class ProductPipeline(object):      def open_spider(self, spider):         if isinstance(spider, JdProductSpider):             # 建立MongoDB数据库链接             self.client = MongoClient(MONGO_URL)             # 获取要操作集合             self.category = self.client["jd"]["product"]      def process_item(self, item, spider):         if isinstance(spider, JdProductSpider):             # 把数据插入到mongo中             self.category.insert_one(dict(item))          return item      def close_spider(self, spider):         """关闭"""         if isinstance(spider, JdProductSpider):             self.client.close()8.2 在settings.py中开启这个管道ITEM_PIPELINES = {    "mall_spider.pipelines.CategoryPipeline": 300,     # 开启商品管道    "mall_spider.pipelines.ProductPipeline": 301, }九、实现下载器中间件
  为了避免IP反爬, 我们实现随机User-Agent和代理IP的中间件 步骤  : 实现随机User-Agent的中间件 实现代理IP中间件 在settings.py 文件开启, 下载器中间件 9.1 实现随机User-Agent的中间件步骤  准备User-Agent列表 在middlewares.py中, 实现RandomUserAgent类 实现process_request方法 如果是请求是  https://cdnware.m.jd.com   开头的, 就是设置一个iPhone的user-agent 否则从User-Agent列表中随机取出一个 代码 import requests import random  # 准备请求头 USER_AGENTS = [     "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",     "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",     "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",     "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)",     "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",     "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",     "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",     "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",     "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",     "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",     "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",     "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5",     "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6",     "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",     "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20",     "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52",     "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11",     "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER",     "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)",     "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)",     "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 LBBROWSER",     "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)",     "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)",     "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)",     "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; 360SE)",     "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)",     "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)",     "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1",     "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1",     "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; zh-cn) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5",     "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b13pre) Gecko/20110307 Firefox/4.0b13pre",     "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:16.0) Gecko/20100101 Firefox/16.0",     "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11",     "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10" ]  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)9.2 实现代理IP中间件步骤  : 在middlewares.py中, 实现ProxyMiddleware类 实现process_request方法 从代理池中获取一个随机的代理IP, 需指定代理IP的协议, 和访问的域名 设置给request.meta["proxy"] 实现process_exception方法 当请求出现异常的时候, 代理池哪些代理IP在本域名下是不可以用的 代码  """ 9.2. 实现代理IP中间件 步骤:     在middlewares.py中, 实现ProxyMiddleware类     实现process_request方法     从代理池中获取一个随机的代理IP     设置给request.meta["proxy"] """ from twisted.internet import defer from twisted.internet.error import TimeoutError, DNSLookupError,          ConnectionRefusedError, ConnectionDone, ConnectError,          ConnectionLost, TCPTimedOutError from twisted.web.client import ResponseFailed from scrapy.core.downloader.handlers.http11 import TunnelError  class ProxyMiddleware(object):      EXCEPTIONS_TO_RETRY = (defer.TimeoutError, TimeoutError, DNSLookupError,                            ConnectionRefusedError, ConnectionDone, ConnectError,                            ConnectionLost, TCPTimedOutError, ResponseFailed,                            IOError, TunnelError)      def process_request(self, request, spider):         """         从代理池中获取一个随机的代理IP          设置给request.meta["proxy"]         """         response = requests.get("http://localhost:6868/random?protocol=https&domain=jd.com")         request.meta["proxy"] = response.content.decode()         request.meta["dont_redirect"] = True         return None     def process_exception(self, request, exception, spider):         if isinstance(exception, self.EXCEPTIONS_TO_RETRY):             # 获取代理IP             proxy = request.meta["proxy"]             # 提取IP地址             ip = re.findall("https://(.+):d+", proxy)[0]              params = {               "ip": ip,               "domain": "jd.com"             }              requests.get("http://localhost:6868/disable_domain", params=params)             # 构建请求返回             req = request.copy()             req.dont_filter = True             return req9.3 在settings.py中开启上面的两个下载器中间件# 配置下载器中间件     DOWNLOADER_MIDDLEWARES = {     "mall_spider.middlewares.RandomUserAgent": 500,     "mall_spider.middlewares.ProxyMiddl eware": 543,     }

浅谈两宋时期经济思想的发展提及钱荒两个字很多人会联系到贫穷两个字,可是鲜有人知晓经济高度发展的宋朝也会出现钱荒问题,甚至于还因为钱荒引发了一场财政制度改革。根据历史的记载,早在北宋以前钱荒就已经出现了,只不与人相处要懂人性弱点林肯直到去世都没把一封斥责他人的信寄出点击右上角关注,与大喜一起多读书,读好书!年轻时期的总统林肯,不仅侮辱甚至还通过写信写诗来讽刺嘲笑过他人。经过一些事后,林肯不再随意批评别人,但是米德将军在南北战争中的表现让林肯大燕王的臂膀朱能靖难之役横扫千军,没有他就没有永乐皇帝辅吾成大业者,能也。朱棣朱能,明朝初期朱棣麾下的大将之一,靖难之役中功劳算的上是居功至伟,后被朱棣亲自封为国公,可以说在永乐年间的四大国公中都是佼佼者。自追随朱棣开始,朱能就为他立大多数人属于寒门还是庶民?放到古代属于社会阶层的第几级?我们在影视作品中经常会听到皇帝将某人贬为庶民,就以为这个人到了社会的最底层了,无地无房生活困难,其实这大错特错。士族和庶民士庶二字由来已久,士族中的士,原义是从事耕作的男子,但在西A吃A!连锁家居龙头或易主连锁家居大佬红星美凯龙或将易主。1月8日,宣布筹划控制权变更仅隔一天的美凯龙便更新了本次易主方案的最新细节来自厦门的实力国企建发股份计划拿下美凯龙不超过30股权。建发股份美凯龙双双信托业首份2022年度业绩快报出炉陕国投实现净利润同比增2421世纪经济报道记者朱英子综合报道1月8日晚间,陕西省国际信托股份有限公司(000563。SZ下称陕国投)发布2022年度业绩快报。快报显示,陕国投2022年度实现营业总收入18。稳运力助复苏!美团配送向骑手投入5亿春节稳岗补贴今年是上海骑手王军第一年留在上海过年,他表示,今年春节,上海政府补贴加上平台补贴,收入预计可以比平时多一倍,希望能在假期7天赚够7000元,过完年再去和家人团聚,那时候站点运力恢复东部战区位台岛周边海空域组织诸军兵种联合战备警巡和实战化演练东部战区位台岛周边海空域组织诸军兵种联合战备警巡和实战化演练东部战区新闻发言人施毅陆军大校表示,1月8日,中国人民解放军东部战区位台岛周边海空域组织诸军兵种联合战备警巡和实战化演练15轮投票艰难上任,金灿荣预言麦卡锡为自保,对中国出手会更狠美国当地时间1月7日凌晨,历经15轮艰难投票,麦卡锡终于成功当选众议院议长。这位美国一百年来最难产的众议长,不惜在多个问题上向议会作出重大让步,才换来最后的呱呱坠地。最大的妥协是,揭秘!如果你在古代出海航行,靠什么回家?纪录片如果国宝会说话中讲述了一段古代福船的海上往事。南宋末年,主人公阿丘是一名舟师,负责福船的领航。因为泉州人多地贫难以耕种,阿丘的祖辈决定造条船,拼一把,到海的那边去寻找生机。造TOP102022年体坛十大经典比赛10勇士10797凯尔特人(2022年NBA总决赛G4)唯一上榜的NBA比赛,也是整个202122赛季NBA总决赛的转折点,这届总决赛中的塔图姆成了近十年来表现最差的球队老大(甚至
冒顿单于调戏吕后做我老婆吧?吕后别嘚瑟,有你哭的那天刘邦刚崩驾不久,吕后眼的泪未干,就到收了匈奴顿冒单于一的封来信,信以中十分浮轻的语气说我生塞于外荒蛮之地,整天牛放牧十马分寂寞,如今死你了丈夫,而我死又了老婆,要不俩咱见一面,畅谈毛人凤的后代结局如何?大儿子成富士康董事长,三儿子是爱国华侨1956年初冬的一个午后,原国民政府军统局局长毛人凤在服下一剂中药后,突然感觉腹部剧痛,同时伴随着呕吐腹泻等症状,很快毛人凤就失去了神志,家人赶忙将他送去了医院,经过检查,毛人凤的山村记忆童年的那些事文王广才图片来自网络每逢周末,在公园里散步,看着孩子们在草坪里嬉戏,在游乐场欢声笑语,在花树下等着让大人拍照,深感现在的孩子们真幸福,也不由地想起在农村儿时的往事。逮蝴蝶在上世纪六排名第13位,周冠宇积分依然为零文羊城晚报全媒体记者梁劲松3月20日,2023年F1沙特站正赛在吉达赛道结束,卫冕冠军佩雷兹从杆位发车后几乎一路领跑,最终夺得冠军。中国车手周冠宇排名第13位,又一次无缘积分。周冠北京亮马河游船开启2023年首航3月18日,人们在亮马河游船上欣赏演出。当日,位于北京市朝阳区的亮马河游船旅游项目开启2023年首航。亮马河游船航线达6公里,沿线途径燕莎码头蓝色港湾红领巾公园等多处商圈公园,同时人民日报曾说垛田油菜,全国挂帅,你知道什么是垛田吗?春天到了,气候越来越暖和了,是该出去走走了。江苏一位朋友跟我说,那就去兴化垛田看看吧,那里万岛耸立,千河纵横,是中国真正意义上的水乡。江苏兴化千岛菜花风景区又说,再过几天,油菜花就狂飙高启强安长林孟德海,剧中的原型故事你知道多少?由张译张颂文张志坚吴刚倪大红郝平高叶贾冰李健等人主演的刑侦剧狂飙播出以后,很多网友都在猜测,剧中的人物有没有原型。其实,狂飙里的很多剧情,都是根据真实的社会事件和民生问题为素材而改11年前,一张父子照火遍全国,如今他们的故事比照片还感人父兮生我,母兮鞠我。抚我畜我,长我育我,顾我复我,出入腹我。父母子之爱子,则为之计深远,曾有曾子为孩子信守诺言而斩杀家中的猪,亦是此可言明父母对孩子未来绸缪。世界上每个人幼年之时,连环画金玉姬(河北美术出版社)姚鸿发绘。。。。。。中国故事当工程师遇到宇宙订单视频加载中行星发动机太空电梯外骨骼机器人钢铁螳螂电影流浪地球2用精彩的视效呈现出大开脑洞的场景。你们尽管想象,我们负责实现。当中国工程师遇到宇宙订单,他们凭借超凡的中国智造,让科幻突发!又一只巨老虎涉嫌严重违纪违法被查!长的真是一表人才人不能把钱带进坟墓,但钱却能把人带进坟墓。最近几年,有些银行的奇怪规定让人印象深刻。因此很多网民抱怨只许州官放火,不许百姓点灯,大家早就对此不满了。三月十六日晚,又一只大虎被山东省