##用python爬京东商品(一)
一、环境准备
python3.7 + scrapy1.5
- 安装Anaconda(里面包含python,安装过程略)
- 从conda-forge安装scrapy(可以减少相应的包依赖的问题)
conda install -c conda-forge scrapy - 安装ide,这里推荐pyCharm
二、总体流程
- 创建项目
命令行终端,进入一个目录,使用scrapy命令创建项目jdproject,
scrapy startproject jdproject - pyCharm配置环境
进入Preferences -> Project -> Project interpreter,选择Anaconda下的python版本(/anaconda3/bin/python3.7)
- 目录结构
jdproject/spiders 这个文件夹是用来放具体执行爬虫程序的
jdproject/items.py 这个文件用来定义返回item实体,例如商品product的name,id和price等
jdproject/middlewares.py 这个文件用来放中间件处理类,例如downloaderMiddlewares和spiderMiddlewares
jdproject/pipelines.py 这个文件里定义处理item的类,例如将item写入数据库
jdproject/settings.py 这个文件里设置了项目的一些参数,例如开启商品管道pipline:ITEM_PIPELINES = { ‘jdproject.pipelines.JdProductPipeline’: 300 }
- scrapy组件和工作流程
组件component:
Scrapy Engine:负责控制系统中所有组件的数据流,当某个action发生时触发事件
Scheduler:接受来之于Engine的请求并且给他们排队,并进行调度
Downloader:负责抓取网页上的数据
Spiders:用户解析响应(然后封装item)的自定义classes
Item Pipeline:负责处理用户封装好item,典型的任务包括清理、验证和持久化(将数据写入mongo)
Downloader middlewares:位于Engine和Downloader的中间件,可以在请求从Engine发送到Downloader时处理请求、可以在响应数据返回到Downloader时处理,还可以干很多事
例如偷偷的更换一个请求等
Spider middlewares:位于Engine和Spiders的中间件,后处理callback,新增,修改和删除请求和item,或者处理一些spider的异常
工作流程work flow:
1⃣Spiders发送原生的请求到Engine
2⃣Engine将请求交给Scheduler进行调度
3⃣Scheduler将要执行的请求返回给Engine
4⃣Engine拿到这个请求发送给Downloader去抓去网页数据,这个过程要经过中组件Downloader middlewares的处理(重写middlewares.py对应的类里的proess_request方法)
5⃣当Downloader下载完数据后产生一个响应返回给Engine,这个过程要经过中组件Downloader middlewares的处理(重写middlewares.py对应的类里的proess_response方法)
6⃣Engine将拿到的数据返回给Spiders的parse进行处理,这个过程要经过中组件Spider middlewares的处理(重写middlewares.py对应的类里的process_spider_input方法)
7⃣spiders处理完并生成对应的item发送给Engine,这个过程要经过中组件Spider middlewares的处理(重写middlewares.py对应的类里的process_spider_output方法)
8⃣Engine将处理完的item发送给Item Pipeline,并且告诉Scheduler执行下一个crawl请求
9⃣重复执行上述步骤,直到Scheduler没有可执行的请求
三、代码实现
有了上面的介绍,相信大家对具体的流程有了一定的了解,这里先爬一个简单的商品类别,包括id,pid,name,url
- 编写productType_spiders.py
response.css(‘div.category-item’) 查找class = category-item的div
pta.css(‘div.mt span::text’).extract_first() 提取div下 第一个span标签的value
具体用法可以参考官方文档,类似的还有xpath和正则
核心代码:
class JDProductTypeSpider(scrapy.Spider):
name = 'jdpt'
start_urls = [
'https://www.jd.com/allSort.aspx'
]
def parse(self, response):
ptItem1 = ProductTypeItem()
ptItem2 = ProductTypeItem()
ptItem3 = ProductTypeItem()
# 一级类别
for pta in response.css('div.category-item'):
ptItem1['name'] = pta.css('div.mt span::text').extract_first()
ptItem1url = pta.css('div.items .clearfix dt a::attr(href)').extract_first()
ptItem1['pid'] = 0
ptItem1['id'] = ptItem1url.split('/')[-1].split('.')[0].split('-')[0]
# print(ptItem1)
# 二级类别
for ptb in pta.css('div.items .clearfix'):
ptItem2['name'] = ptb.css('dt a::text').extract_first()
ptItem2url = ptb.css('dt a::attr(href)').extract_first()
ptItem2['url'] = ptItem2url
# print(ptItem2)
# 三级类别
for ptc in ptb.css('dd a'):
ptItem3['name'] = ptc.xpath('text()').extract_first()
ptItem3url = ptc.xpath("@href").extract_first()
ptItem3['url'] = ptItem3url
try:
if ptItem3url.count('?') > 0:
ppids = ptItem3url.split('?')[-1].split('=')[-1].split(',')
if len(ppids) == 3:
ptItem3['id'] = ppids[2]
ptItem3['pid'] = ppids[1]
ptItem2['id'] = ppids[1]
ptItem2['pid'] = ppids[0]
ptItem1['id'] = ppids[0]
elif len(ppids) == 2:
#print(ppids)
ptItem2['id'] = ppids[1]
ptItem2['pid'] = ppids[0]
ptItem1['id'] = ppids[0]
else:
#print(ptItem3url)
if ptItem3url.count('&'):
ttids = ptItem3url.split('&')[0].split('?')[-1].split('=')[-1].split(',')
if len(ttids) == 2:
# print(ttids)
ptItem2['id'] = ttids[1]
ptItem2['pid'] = ttids[0]
ptItem1['id'] = ttids[0]
else:
#print(ptItem3url)
if ptItem3url.count('-') > 0:
ptItem2['id'] = ptItem3url.split('/')[-1].split('.')[0].split('-')[1]
ptItem2['pid'] = ptItem3url.split('/')[-1].split('.')[0].split('-')[0]
ptItem1['id'] = ptItem3url.split('/')[-1].split('.')[0].split('-')[0]
except Exception:
#print(ptItem3url)
pass
print(ptItem3)
yield ptItem3
print("----------------")
print(ptItem2)
yield ptItem2
print("++++++++++++++++++++++++++++++++++")
print(ptItem1)
yield ptItem1
- 编写items.py
核心代码:
class ProductTypeItem(scrapy.Item):
id = scrapy.Field()
pid = scrapy.Field()
name = scrapy.Field()
url = scrapy.Field()
pass
- 编写pipelines.py 将items数据入库
需要安装pymongo
pip install pymongo
核心代码:
class JdprojectPipeline(object):
def __init__(self):
client = pymongo.MongoClient('127.0.0.1', 27017)
db = client['jd']
self.post = db['category']
def process_item(self, item, spider):
if isinstance(item, ProductTypeItem):
postItem = dict(item)
self.post.insert(postItem)
print("jdpt")
else:
print("other")
return item
- 编写settings.py
开启上述几项配置开启上述几项配置
ITEM_PIPELINES = {
'jdproject.pipelines.JdprojectPipeline': 300,
}
- 执行代码
进入项目根目录: cd ./jdproject
执行crawl命令:scrapy crawl jdpt (这里的jdpt对应为类JDProductTypeSpider里的name)
在pyCharm调试和执行配置:
右上角 -> Edit configurations
四、代码链接
https://github.com/jieYW/jdproject
五、官方文档
https://docs.scrapy.org/en/latest/