You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pf3x5aziv 2ccd0f93d6
Add readme无法线上查看, 需要clone查看
3 years ago
.idea finish 3 years ago
img finish 3 years ago
jdSearchSpider finish 3 years ago
jdSkuSpider finish 3 years ago
.gitignore finish 3 years ago
LICENSE finish 3 years ago
README.md Update README.md 3 years ago
readme无法线上查看, 需要clone查看 Add readme无法线上查看, 需要clone查看 3 years ago

README.md

京东显卡商品信息分布式爬虫

介绍

本爬虫分两个部分:

  • 第一部分搜索页爬虫是使用selenium爬取搜索页, 主要获取的是商品的sku和价格

  • 第二部分商品页爬虫使用scrapy爬取详情页的商品介绍信息, 主要获取商品的型号

由于京东商品种类繁多, 不同的商品品类间差异巨大, 商品页爬虫的代码也就不近相同. 出于成本和时间考虑, 搜索页爬虫使用3080作为搜索关键词, 商品页爬虫爬取搜索页爬虫获取的商品对应的详情页

其整体架构如下:

电商网站筛选

爬虫的目的就是为了获取一定量的有价值的信息, 就目前中文互联网来说, 电商网站是信息密度和价值密度比较高的地方, 因此使用爬虫获取信息有一定的可用性.

目前而言, 淘宝获取的商品信息结果层次最多, 品类最全. 但是首先淘宝商品搜索页混杂天猫,天猫国际, 淘宝卖家等各类各不相同的店铺, 因此其商品详情页结构也大相径庭; 其次是淘宝历史包袱比较重, 因此有许多结构混乱的页面混杂其中, 难以提取数据.

因此, 实际考虑后确认, 淘宝不是太适合新人小团队去学习试炼爬虫爬取信息.

相对而言, 京东搜索页基本同一为京东自己的页面, 京东自营, 旗舰店和商家店结构基本没有区别, 详情页结构也一致, 对爬虫比较友好(京东唯一不太友好的地方只有, 其主站页面下并没有写robots.txt). 因此考虑爬取京东.

搜索页爬虫

主要由settings.yamljdSearchSeleniumSpider.py两部分组成,settings.yaml是配置文件, jdSearchSeleniumSpider.py是代码执行主体

前期工作

基本而言, 任何有搜索功能的网站都会对其搜索功能做一定的限制, 以防止单个ip过高频率的访问, 占用过多资源.

京东也不例外, 对于未登录的请求, 甚至是带着header和cookie的请求, 往往都是秉持拒绝的态度, 要求验证登录:

搜索引擎的爬虫验证一般级别都比较高, 难以绕过. 考虑到搜索页的数量相对于商品页的数量往往是少一个数量级, 且京东单个搜索词的页面量也大致在几十几百页的数量级之间, 因此使用python的selenium库, 驱动浏览器去自动化访问搜索页, 进而获取数据, 是比较简单且可行的方案.

settings.yaml

setting.yaml是搜索页爬虫的配置文件, 其内容如下:

search:
  keyword: '3080'
  sleep: 5

redis: 
  host: '120.24.87.40'
  port: '6379'
  password: 'Guet@207'
  db: 1

mongodb:
  host: '120.24.87.40'
  port: '27017'
  username: "admin"
  password: "123456"

result:
  rpush_key: "jd:start_urls"
  • search

    • keyword: 要搜索的关键字, 即在京东商品搜索上的要搜索的商品;

    • sleep: 休眠时间, 单位: 秒; 由于selenium操作页面的动作(例如点击翻页, 下拉)是异步的, 而读取页面是同步的. 京东需要执行下拉这个操作后才加载出所有的商品信息, 为了读取全当前的页面信息, 需要休眠一段时间等待异步操作完成;

  • redis

    • host: redis部署的服务器地址;

    • port: redis部署时开放的端口号;

    • password: redis部署时设置的auth;

    • db: 需要使用redis的第几个数据库

  • mongodb

    • host: MongoDB部署的服务器地址;

    • port: MongoDB部署时开放的端口号;

    • username: MongoDB部署时设置的auth的用户名, 或者说要使用的MongoDB的数据库名;

    • password: MongoDB部署时设置的auth.

  • result

    • rpush_key: 爬虫获取到的数据形成的url要放入redis时设置的key, url在Redis中存储方式是列表

jdSearchSeleniumSpider.py

搜索页爬虫的程序入口, 根据京东搜索页面爬取页面元素.

启动程序后进入京东的商品搜索页面. 搜索页的搜索关键字为settings.py中设定的search.keyword.

京东的搜索页面会分两个阶段加载, 第一个加载阶段加载成功后(即加载出30个商品的信息), 爬虫会执行scroll_by_xpath(), 作用是滚动网页到网页底部, 触发京东搜索页面的第二个加载阶段, 把一个页面上的信息都加载到浏览器里.

scroll_by_xpath() 内部原理就是驱动浏览器移动视图, 使视图可以看到指定的元素. 在该爬虫中, 指定的网页元素的xpath//*[@id="J_bottomPage"]/span[1]/a[9], 代表的是京东搜索页面的下一页按钮这一网页元素.

两个阶段都加载完成后, 获取网页中所有商品的sku和价格.

sku是京东给商品的编号, 且可以根据sku拼接对应商品的详情页的URL.

获取到sku和价格后, 将sku拼接为URL, rpush到Redis设置好的数据库的result.rpush_key中, 并且将每个商品的数据以{'sku': sku, 'price': price}的形式, 放入MongoDB设置好的数据库中. 放入MongoDB前会根据sku字段查询数据是否存在(原子操作, 可分布式), 防止重复插入.

商品页爬虫

商品页爬虫使用了scrapy_redis去写, 即Scrapy的redis版本, 他与Scrapy的主要区别就是把存放URL于Reids数据库中, 利用Redis的特性, 即在多个请求请求同一个数据时, 会默认对请求排序, 有一个队列效果, 保证了分布式爬虫获取到不同的URL.

scrapy_redis框架下的爬虫执行是异步的, 即, 从Redis数据库的列表中获取URL后, 发起Request, 便可以执行下一次从Redis中获取Redis, 而发起Request得到的response则等得到后再由回调函数处理(即执行jdsku.py里的parse方法).

该爬虫只需要在本爬虫目录下, 调用scrapy crawl jdsku即可启动.

settings.py

配置文件, 具体配置查看Scrapy的配置, 其中有几个是scrapy_redis的配置或本次项目引入的配置, 在此说明:

个人配置:

PROXY_SERVER_URL: IP代理商提供的直连IP的API地址;

TEST_PAGE: 用于测试IP代理商提供的IP代理服务是否能访问JD的测试地址, 可以按需更换不同的京东商品地址;

mongodb: 配置时需要以字典形式配置

  • host: MongoDB服务器的地址;

  • port: MongoDB服务器暴露的端口;

  • username: MongoDB要使用的用户名(也是数据库名)

  • password: MongoDB对应用户名的验证密码

cookies: 浏览器访问京东时的cookies, 有助于模拟浏览器访问, 降低失败率

scrapy_redis配置:

DONT_FILTER: Redis访问不去重, True代表不去重. 不去重的原因是使用代理访问商品详情页时可能会失败, 此时会将URL重新放回Redis的列表开头;

SCHEDULER='scrapy_redis.scheduler.Scheduler': 使用scrapy_redis中的调度器, 即保证每台主机爬取的URL地址都不同的Scheduler.

DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter': 配置scrapy使用的去重类, 即RFPDupeFilter.

SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat": 使用scrapy_redis.picklecompat作为序列化, 不序列化的数据可能会出现乱码.

   AUTOTHROTTLE_ENABLED = True: 开启自动限速, 控制爬取速度,降低对方服务器压力.

items.py

代码如下:

import scrapy


class JdskuspiderItem(scrapy.Item):
    # sku-id
    sku = scrapy.Field()
    # title
    title = scrapy.Field()
    # 显卡型号
    model = scrapy.Field()
    # 显存类型
    memoryType = scrapy.Field()
    # 显存位宽
    bitWidth = scrapy.Field()
    # 显存容量
    memoryCapacity = scrapy.Field()

item是爬虫数据的容器, 方便我们按对应字段存储数据

jdsku.py

商品页爬虫的程序入口, 根据redis数据库对应的列表访问对应URL, 在京东商品详情页面爬取页面元素. 因为使用scrapy_redis框架, 也就是Scrapy的Redis分布式版本, 因此大部分代码都是在重写方法.

对于class JdskuSpider(RedisSpider):

属性:

name: 爬虫的名字, 后续在终端启动爬虫时需要输入的爬虫名;

allowed_domains: 运行爬取的URL范围;

redis_key: Redis数据库中存放要爬取的URL的列表的Key名, 会获取列表中的第一个数据;

redis_connection: 存放一个新的Redis连接, 该连接后续用于访问失败时重新把URL返回给Redis列表;

mongo_connection: 存放一个新的MongoDB连接, 该连接后续用于存放最终数据.

方法:

两个方法都是重写方法, 方法名和参数都固定, 两个方法都是自动调用.

make_requests_from_url(self, url):

  • scrapy_redis框架会调用该方法, 发起一个访问参数里URL的request, 返回一个response, 框架会将response发给他的回调函数处理(即下述的parse);

  • meta={'url':url}表示会将{'url': url}作为数据传递下去, 这样在他的回调函数(parse)里就能使用到该数据.

parse(self, response):

  • scrapy_redis发送的请求得到response后的回调函数;

  • 作用是解析商品详情页(针对特定商品), 提取数据, 并将其保存到MongoDB中, 若提取数据表现出来的是被京东拦截, 那么把该次访问的URL重新返回到Redis列表开头.