zoukankan      html  css  js  c++  java
  • 爬虫系列(十三) 用selenium爬取京东商品

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

    1、网页分析

    (1)初步分析

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

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

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

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

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

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

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

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

    (2)模拟翻页

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

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

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

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

    (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')

    2、编码实现

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

    from selenium import webdriver
    from selenium.webdriver.support.wait import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By
    import selenium.common.exceptions
    import json
    import csv
    import time
    
    class 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('----------------------------------------
    ')
                    self.fd.write('link:' + str(item[0]) + '
    ')
                    self.fd.write('price:' + str(item[1]) + '
    ')
                    self.fd.write('name:' + str(item[2]) + '
    ')
                    self.fd.write('comment:' + str(item[3]) + '
    ')
            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)
    

    【爬虫系列相关文章】

    版权声明:本博客属于个人维护博客,未经博主允许不得转载其中文章。
  • 相关阅读:
    F4搜索帮助 带回多个值
    ALV Tree demo(WBS元素分层显示)[引用别人的]
    WDA导出文件XLS,WORD
    采购信息记录修改[BDC]
    增强:MB1A物料价格检查
    机器学习中常见优化方法汇总
    统计模型机器学习模型领域相关知识,指标概念及问题点积累
    机器学习数学知识中令人费解的notation符号注解
    线性代数的视角理解LSR(least square regression)的参数评估算法本质
    statsmodels中的summary解读(以linear regression模型为例)
  • 原文地址:https://www.cnblogs.com/wsmrzx/p/9556543.html
Copyright © 2011-2022 走看看