|
3 years ago | |
---|---|---|
.idea | 3 years ago | |
img | 3 years ago | |
jdSearchSpider | 3 years ago | |
jdSkuSpider | 3 years ago | |
.gitignore | 3 years ago | |
LICENSE | 3 years ago | |
README.md | 3 years ago | |
readme无法线上查看, 需要clone查看 | 3 years ago |
README.md
京东显卡商品信息分布式爬虫
介绍
本爬虫分两个部分:
-
第一部分搜索页爬虫是使用selenium爬取搜索页, 主要获取的是商品的sku和价格
-
第二部分商品页爬虫使用scrapy爬取详情页的商品介绍信息, 主要获取商品的型号
由于京东商品种类繁多, 不同的商品品类间差异巨大, 商品页爬虫的代码也就不近相同. 出于成本和时间考虑, 搜索页爬虫使用3080作为搜索关键词, 商品页爬虫爬取搜索页爬虫获取的商品对应的详情页
其整体架构如下:
电商网站筛选
爬虫的目的就是为了获取一定量的有价值的信息, 就目前中文互联网来说, 电商网站是信息密度和价值密度比较高的地方, 因此使用爬虫获取信息有一定的可用性.
目前而言, 淘宝获取的商品信息结果层次最多, 品类最全. 但是首先淘宝商品搜索页混杂天猫,天猫国际, 淘宝卖家等各类各不相同的店铺, 因此其商品详情页结构也大相径庭; 其次是淘宝历史包袱比较重, 因此有许多结构混乱的页面混杂其中, 难以提取数据.
因此, 实际考虑后确认, 淘宝不是太适合新人小团队去学习试炼爬虫爬取信息.
相对而言, 京东搜索页基本同一为京东自己的页面, 京东自营, 旗舰店和商家店结构基本没有区别, 详情页结构也一致, 对爬虫比较友好(京东唯一不太友好的地方只有, 其主站页面下并没有写robots.txt). 因此考虑爬取京东.
搜索页爬虫
主要由settings.yaml
和jdSearchSeleniumSpider.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列表开头.