本篇目标:我们以爬取京东商城商品数据为例,展示Scrapy框架对接selenium爬取京东商城商品数据。

背景:

  京东商城页面为js动态加载页面,直接使用request请求,无法得到我们想要的商品数据,故需要借助于selenium模拟人的行为发起请求,输出源代码,然后解析源代码,得到我们想要的数据。

第一步:设置我们需要提取的字段,也就是在Scrapy框架中设置Item.py文件。

class ProductItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
dp = Field()
title = Field()
price = Field()
comment=Field()
url=Field()
type=Field()
这里我们需提取上面几个字段,依次为店铺名称,商品名称,商品价格,评论数,商品url,类型(区分是什么类型的商品)

第二步:
  设置我们需要从哪个页面开始爬起,也就是开发scrapy框架中的spider文件,代码如下
class JingdongSpider(scrapy.Spider):
name = 'jingdong'
allowed_domains = ['www.jingdong.com']
base_url = 'https://search.jd.com/Search?keyword=' def start_requests(self):
for keyword in self.settings.get('KEYWORDS'):
for page in range(1,self.settings.get('MAX_PAGE') + 1):
url = self.base_url + quote(keyword)
#dont_filter = True 不去重
yield Request(url = url ,callback = self.parse,meta = {'page':page},dont_filter=True)
  我们设置初始url为京东商城搜索商品的页面链接,其中搜索的商品用KEYWORDS表示,在settings文件中以列表的形式设置,因为搜索出来的页数可能很多,所有我们需要爬取的页数页用MAX_PAGE变量
在settings文件中设置。
KEYWORDS=['iPad']
MAX_PAGE=2

如果此时运行项目,链接会直接发送给下载器进行下载,无法得到我们想要的数据,所以我们在下载器中间件中对该请求进行处理。

第三步:
  在下载器中间件中对接selenium,直接输出源代码并返回,不在下载器中下载页面。
class SeleniumMiddleware(object):
# Not all methods need to be defined. If a method is not defined,
# scrapy acts as if the downloader middleware does not modify the
# passed objects. def __init__(self,timeout=None):
self.logger=getLogger(__name__)
self.timeout = timeout
self.browser = webdriver.Chrome()
self.browser.set_window_size(1400,700)
self.browser.set_page_load_timeout(self.timeout)
self.wait = WebDriverWait(self.browser,self.timeout) def __del__(self):
self.browser.close() @classmethod
def from_crawler(cls, crawler):
# This method is used by Scrapy to create your spiders.
return cls(timeout=crawler.settings.get('SELENIUM_TIMEOUT')) def process_request(self, request, spider):
'''
在下载器中间件中对接使用selenium,输出源代码之后,构造htmlresponse对象,直接返回
给spider解析页面,提取数据
并且也不在执行下载器下载页面动作
htmlresponse对象的文档:
:param request:
:param spider:
:return:
''' print('Chorme is Starting')
page = request.meta.get('page', 1)
self.wait = WebDriverWait(self.browser, self.timeout)
try:
self.browser.get(request.url)
if page > 1:
input = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#J_bottomPage > span.p-skip > input')))
input.clear()
input.send_keys(page)
time.sleep(5) # 将网页中输入跳转页的输入框赋值给input变量 EC.presence_of_element_located,判断输入框已经被加载出来
input = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#J_bottomPage > span.p-skip > input')))
# 将网页中调准页面的确定按钮赋值给submit变量,EC.element_to_be_clickable 判断此按钮是可点击的
submit = self.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_bottomPage > span.p-skip > a')))
input.clear()
input.send_keys(page)
submit.click() # 点击按钮
time.sleep(5) # 判断当前页码出现在了输入的页面中,EC.text_to_be_present_in_element 判断元素在指定字符串中出现
self.wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, '#J_bottomPage > span.p-num > a.curr'),str(page)))
# 等待 #J_goodsList 加载出来,为页面数据,加载出来之后,在返回网页源代码
self.wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, '#J_bottomPage > span.p-num > a.curr'),str(page)))
return HtmlResponse(url=request.url, body=self.browser.page_source, request=request, encoding='utf-8',status=200)
except TimeoutException:
return HtmlResponse(url=request.url, status=500, request=request)
__init__和类函数都执行一些初始化操作,无需多说,我们主要看process_request()方法
首先我们这是浏览器的等待时长,然后我们见输入页码的输入框赋值给input变量,在将翻页的点击按钮框赋值给submit变量,然后在数据框中输入页码,等待页面加载,直接返回
htmlresponse给spider解析,这里我们没有经过下载器下载,直接构造response的子类htmlresponse返回。(当下载器中间件返回response对象时,更低优先级的process_request将不在执行,转而
执行其他的process_response()方法,本例中没有其他的process_response(),所以直接将结果返回给spider解析。) 第四步:
  开发第二步中Request对象中的回调函数,解析页面数据,提取我们想要的数据。这里我们采用BeautifulSoup进行解析,代码如下:
def parse(self, response):
soup = BeautifulSoup(response.text, 'lxml')
lis = soup.find_all(name='li', class_="gl-item")
for li in lis:
proc_dict = {}
dp = li.find(name='span', class_="J_im_icon")
if dp:
proc_dict['dp'] = dp.get_text().strip()
else:
continue
id = li.attrs['data-sku']
title = li.find(name='div', class_="p-name p-name-type-2")
proc_dict['title'] = title.get_text().strip()
price = li.find(name='strong', class_="J_" + id)
proc_dict['price'] = price.get_text()
comment = li.find(name='a', id="J_comment_" + id)
proc_dict['comment'] = comment.get_text() + '条评论'
url = 'https://item.jd.com/' + id + '.html'
proc_dict['url'] = url
proc_dict['type'] = 'JINGDONG'
yield proc_dict
第五步:
  提取完页面数据之后,数据会发送到item pipeline处进行数据处理,清洗,入库等操作,所以我们此时当然需要定义项目管道了,在此我们将数据存储在mongodb数据库中。
class MongoPipeline(object):

    def __init__(self,mongo_url,mongo_db,collection):
self.mongo_url = mongo_url
self.mongo_db = mongo_db
self.collection = collection @classmethod
def from_crawler(cls,crawler):
return cls(
mongo_url=crawler.settings.get('MONGO_URL'),
mongo_db = crawler.settings.get('MONGO_DB'),
collection = crawler.settings.get('COLLECTION')
) def open_spider(self,spider):
self.client = pymongo.MongoClient(self.mongo_url)
self.db = self.client[self.mongo_db] def process_item(self,item, spider):
# name = item.__class__.collection
name = self.collection
self.db[name].insert(dict(item))
return item def close_spider(self,spider):
self.client.close()
我们使用类方法from_crawler从settings文件中获取mongodb数据库的配置信息,在__init__中进行初始化,在process_item中将数据存储到mongodb中。

第六步
  1、配置settings文件,将项目中使用到的配置项在settings文件中配置,本项目中使用到了KEYWORDS,MAX_PAGE,SELENIUM_TIMEOUT(页面加载超时时间),MONGOURL,MONGODB,COLLECTION;
  2、修改配置项,激活下载器中间件和item pipeline。
DOWNLOADER_MIDDLEWARES = {
'scrapyseleniumtest.middlewares.SeleniumMiddleware': 543,
} ITEM_PIPELINES = {
'scrapyseleniumtest.pipelines.MongoPipeline': 300,
}
至此,项目中所有需要开发的代码和配置项开发完成,运行项目之后,在mongodb中查看数据,应该已经执行成功。

本项目完整代码:

https://gitee.com/liangxinbin/Scrpay/tree/master/scrapyseleniumtest

												

Scrapy实战篇(八)之Scrapy对接selenium爬取京东商城商品数据的更多相关文章

  1. Scrapy实战篇(七)之Scrapy配合Selenium爬取京东商城信息(下)

    之前我们使用了selenium加Firefox作为下载中间件来实现爬取京东的商品信息.但是在大规模的爬取的时候,Firefox消耗资源比较多,因此我们希望换一种资源消耗更小的方法来爬取相关的信息. 下 ...

  2. 爬虫(十七):Scrapy框架(四) 对接selenium爬取京东商品数据

    1. Scrapy对接Selenium Scrapy抓取页面的方式和requests库类似,都是直接模拟HTTP请求,而Scrapy也不能抓取JavaScript动态谊染的页面.在前面的博客中抓取Ja ...

  3. 利用selenium爬取京东商品信息存放到mongodb

    利用selenium爬取京东商城的商品信息思路: 1.首先进入京东的搜索页面,分析搜索页面信息可以得到路由结构 2.根据页面信息可以看到京东在搜索页面使用了懒加载,所以为了解决这个问题,使用递归.等待 ...

  4. selenium模块使用详解、打码平台使用、xpath使用、使用selenium爬取京东商品信息、scrapy框架介绍与安装

    今日内容概要 selenium的使用 打码平台使用 xpath使用 爬取京东商品信息 scrapy 介绍和安装 内容详细 1.selenium模块的使用 # 之前咱们学requests,可以发送htt ...

  5. 爬虫系列(十三) 用selenium爬取京东商品

    这篇文章,我们将通过 selenium 模拟用户使用浏览器的行为,爬取京东商品信息,还是先放上最终的效果图: 1.网页分析 (1)初步分析 原本博主打算写一个能够爬取所有商品信息的爬虫,可是在分析过程 ...

  6. 利用Selenium爬取淘宝商品信息

    一.  Selenium和PhantomJS介绍 Selenium是一个用于Web应用程序测试的工具,Selenium直接运行在浏览器中,就像真正的用户在操作一样.由于这个性质,Selenium也是一 ...

  7. Scrapy实战篇(四)爬取京东商城文胸信息

    创建scrapy项目 scrapy startproject jingdong 填充 item.py文件 在这里定义想要存储的字段信息 import scrapy class JingdongItem ...

  8. Scrapy实战篇(五)爬取京东商城文胸信息

    创建scrapy项目 scrapy startproject jingdong 填充 item.py文件 在这里定义想要存储的字段信息 import scrapy class JingdongItem ...

  9. 使用Selenium爬取网站表格类数据

    本文转载自一下网站:Python爬虫(5):Selenium 爬取东方财富网股票财务报表 https://www.makcyun.top/web_scraping_withpython5.html 需 ...

随机推荐

  1. 【spring源码分析】BeanDefinitionRegistryPostProcessor解析

    一.自定义BeanDefinitionRegistryPostProcessor BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProces ...

  2. 发布自己的npm包

    如何发布自己写的npm包,这里有详细解释 : https://blog.csdn.net/u010130282/article/details/82629924 本文旨在解释遇到的问题: 1:需要设置 ...

  3. mysql不存在插入否则更新

    1.如果存在就更新,没有就插入,相当于三目运算 CREATE UNIQUE INDEX xxx ON t_msg_user_view(USER_ID); INSERT INTO xxx(user_id ...

  4. sqler sql 转rest api redis 接口使用

    sqler 支持redis 协议,我们可以用过redis client 连接sqler,他会将宏住转换为redis command 实现上看源码我们发现是基于一个开源的redis 协议的golang ...

  5. hasura graphql-engine &&patroni docker-compose 环境运行

    patroni 是一个很不错的pg ha 解决方案,graphql-engine 是一个很好的graphql 工具,为了方便使用 参考patroni官方的文档,使用docker-compose 将应用 ...

  6. mysql-sql语言参考

    字段去重查询 select distinct style from music 批量修改某字段 update music set style = "ost"  where styl ...

  7. Web-Business-Application-Solution

    项目地址 :  https://github.com/kelin-xycs/Web-Business-Application-Solution Web-Business-Application-Sol ...

  8. vue线上项目,优化前后对比

    优化前: dev初次时间:52s dev时间:5s~6s build时间:374s(6.2分钟) build后zip包大小: vue.vue-router 优化后: dev初次时间:49s.48s.5 ...

  9. 关于高并发下kafka producer send异步发送耗时问题的分析

    最近开发网关服务的过程当中,需要用到kafka转发消息与保存日志,在进行压测的过程中由于是多线程并发操作kafka producer 进行异步send,发现send耗时有时会达到几十毫秒的阻塞,很大程 ...

  10. NDK学习笔记(五)Reader机制

    针对每一种后缀名Nuke都提供了对应的模块.为了决定用哪个版本的reader或writer模块,Nuke会先解析文件后缀名再以此为依据调用相关模块. 以JPG为例: 该文件格式有两种后缀名:.jpg和 ...