博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
爬虫系列(十三) 用selenium爬取京东商品
阅读量:5266 次
发布时间:2019-06-14

本文共 6131 字,大约阅读时间需要 20 分钟。

这篇文章,我们将通过 selenium 模拟用户使用浏览器的行为,爬取京东商品信息,还是先放上最终的效果图:

1459925-20190312195538348-2001336016.png

1、网页分析

(1)初步分析

原本博主打算写一个能够爬取所有商品信息的爬虫,可是在分析过程中发现,不同商品的网页结构竟然是不一样的

所以,后来就放弃了这个想法,转为只爬取笔记本类型商品的信息

如果需要爬取其它类型的商品信息,只需把提取数据的规则改变一下就好,有兴趣的朋友可以自己试试看呀

好了,下面我们正式开始!

首先,用 Chrome 浏览器打开 ,我们很容易发现该网页是一个 动态加载 的网页

因为刚打开网页时只会显示 30 个商品的信息,可是当我们向下拖动网页时,它会再次加载剩下 30 个商品的信息

这时候我们可以通过 selenium 模拟浏览器下拉网页的过程,获取网站全部商品的信息

>>> browser.execute_script("window.scrollTo(0,document.body.scrollHeight)")

1459925-20190312195547265-2098879935.png

(2)模拟翻页

另外,我们发现该网站一共有 100 个网页

我们可以通过构造 URL 来获取每一个网页的内容,但是这里我们还是选择使用 selenium 模拟浏览器的翻页行为

下拉网页至底部可以发现有一个 下一页 的按钮,我们只需获取并点击该元素即可实现翻页

>>> browser.find_element_by_xpath('//a[@class="pn-next" and @onclick]').click()

1459925-20190312195554551-2086874241.png

(3)获取数据

接下来,我们需要解析每一个网页来获取我们需要的数据,具体包括(可以使用 selenium 选择元素):

  • 商品 ID:browser.find_elements_by_xpath('//li[@data-sku]') ,用于构造链接地址
  • 商品价格:browser.find_elements_by_xpath('//div[@class="gl-i-wrap"]/div[2]/strong/i')
  • 商品名称:browser.find_elements_by_xpath('//div[@class="gl-i-wrap"]/div[3]/a/em')
  • 评论人数:browser.find_elements_by_xpath('//div[@class="gl-i-wrap"]/div[4]/strong')

1459925-20190312195602072-2137714679.png

2、编码实现

好了,分析过程很简单,基本思路是使用 selenium 模拟浏览器的行为,下面是代码实现

from selenium import webdriverfrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.common.by import Byimport selenium.common.exceptionsimport jsonimport csvimport timeclass JdSpider():    def open_file(self):        self.fm = input('请输入文件保存格式(txt、json、csv):')        while self.fm!='txt' and self.fm!='json' and self.fm!='csv':            self.fm = input('输入错误,请重新输入文件保存格式(txt、json、csv):')        if self.fm=='txt' :            self.fd = open('Jd.txt','w',encoding='utf-8')        elif self.fm=='json' :            self.fd = open('Jd.json','w',encoding='utf-8')        elif self.fm=='csv' :            self.fd = open('Jd.csv','w',encoding='utf-8',newline='')    def open_browser(self):        self.browser = webdriver.Chrome()        self.browser.implicitly_wait(10)        self.wait = WebDriverWait(self.browser,10)    def init_variable(self):        self.data = zip()        self.isLast = False    def parse_page(self):        try:            skus = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//li[@class="gl-item"]')))            skus = [item.get_attribute('data-sku') for item in skus]            links = ['https://item.jd.com/{sku}.html'.format(sku=item) for item in skus]            prices = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="gl-i-wrap"]/div[2]/strong/i')))            prices = [item.text for item in prices]            names = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="gl-i-wrap"]/div[3]/a/em')))            names = [item.text for item in names]            comments = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="gl-i-wrap"]/div[4]/strong')))            comments = [item.text for item in comments]            self.data = zip(links,prices,names,comments)        except selenium.common.exceptions.TimeoutException:            print('parse_page: TimeoutException')            self.parse_page()        except selenium.common.exceptions.StaleElementReferenceException:            print('parse_page: StaleElementReferenceException')            self.browser.refresh()    def turn_page(self):        try:            self.wait.until(EC.element_to_be_clickable((By.XPATH,'//a[@class="pn-next"]'))).click()            time.sleep(1)            self.browser.execute_script("window.scrollTo(0,document.body.scrollHeight)")            time.sleep(2)        except selenium.common.exceptions.NoSuchElementException:            self.isLast = True        except selenium.common.exceptions.TimeoutException:            print('turn_page: TimeoutException')            self.turn_page()        except selenium.common.exceptions.StaleElementReferenceException:            print('turn_page: StaleElementReferenceException')            self.browser.refresh()    def write_to_file(self):        if self.fm == 'txt':            for item in self.data:                self.fd.write('----------------------------------------\n')                self.fd.write('link:' + str(item[0]) + '\n')                self.fd.write('price:' + str(item[1]) + '\n')                self.fd.write('name:' + str(item[2]) + '\n')                self.fd.write('comment:' + str(item[3]) + '\n')        if self.fm == 'json':            temp = ('link','price','name','comment')            for item in self.data:                json.dump(dict(zip(temp,item)),self.fd,ensure_ascii=False)        if self.fm == 'csv':            writer = csv.writer(self.fd)            for item in self.data:                writer.writerow(item)    def close_file(self):        self.fd.close()    def close_browser(self):        self.browser.quit()    def crawl(self):        self.open_file()        self.open_browser()        self.init_variable()        print('开始爬取')        self.browser.get('https://search.jd.com/Search?keyword=%E7%AC%94%E8%AE%B0%E6%9C%AC&enc=utf-8')        time.sleep(1)        self.browser.execute_script("window.scrollTo(0,document.body.scrollHeight)")        time.sleep(2)        count = 0        while not self.isLast:            count += 1            print('正在爬取第 ' + str(count) + ' 页......')            self.parse_page()            self.write_to_file()            self.turn_page()        self.close_file()        self.close_browser()        print('结束爬取')if __name__ == '__main__':    spider = JdSpider()    spider.crawl()

代码中有几个需要注意的地方,现在记录下来便于以后学习:

1、self.fd = open('Jd.csv','w',encoding='utf-8',newline='')

在打开 csv 文件时,最好加上参数 newline='' ,否则我们写入的文件会出现空行,不利于后续的数据处理

2、self.browser.execute_script("window.scrollTo(0,document.body.scrollHeight)")

在模拟浏览器向下拖动网页时,由于数据更新不及时,所以经常出现 StaleElementReferenceException 异常

一般来说有两种处理方法:

  • 在完成操作后使用 time.sleep() 给浏览器充足的加载时间
  • 捕获该异常进行相应的处理

3、skus = [item.get_attribute('data-sku') for item in skus]

在 selenium 中使用 xpath 语法选取元素时,无法直接获取节点的属性值,而需要使用 get_attribute() 方法

4、无头启动浏览器可以加快爬取速度,只需在启动浏览器时设置无头参数即可

opt = webdriver.chrome.options.Options()opt.set_headless()browser = webdriver.Chrome(chrome_options=opt)

【爬虫系列相关文章】

转载于:https://www.cnblogs.com/wsmrzx/p/9556543.html

你可能感兴趣的文章
Http GetPost网络请求
查看>>
SWIFT国际资金清算系统
查看>>
Sping注解:注解和含义
查看>>
站立会议第四天
查看>>
如何快速掌握一门技术
查看>>
利用AMPScript获取Uber用户数据的访问权限
查看>>
vagrant 同时设置多个同步目录
查看>>
python接口自动化28-requests-html爬虫框架
查看>>
生成随机数的模板
查看>>
Mysql 数据库操作
查看>>
转:linux终端常用快捷键
查看>>
A-Softmax的总结及与L-Softmax的对比——SphereFace
查看>>
UVa 11059 最大乘积
查看>>
数组分割问题求两个子数组的和差值的小
查看>>
composer 报 zlib_decode(): data error
查看>>
linux下WPS的使用
查看>>
Web Api 利用 cors 实现跨域
查看>>
hdu 3938 并查集
查看>>
instanceof
查看>>
《深入分析Java Web技术内幕》读书笔记之JVM内存管理
查看>>