linzeX

数据采集第四次大作业

作业一

  • 要求
    熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;
    Scrapy+Xpath+MySQL数据库存储技术路线爬取当当网站图书数据
  • 候选网站:
    http://www.dangdang.com/
  • 输出内容
    MySQL数据库存储和输出格式如下:

结果展示

  • 思路:
    • 1 观察html源码,找到目标信息在li节点下

    • 2 根据子节点结构构建xpath搜索路径

      selector=selector.xpath('//ul[@class="bigimg"]/li')
      ##保存到item
       for i in range(len(selector)):
           ##根据路径提取信息
           name = selector[i].xpath('./a/@title').extract()
           author = selector[i].xpath('./p/span[position()=1]/a[position()=1]/@title').extract()
           poblish = selector[i].xpath('./p/span[position()=3]/a[position()=1]/@title').extract()
           price = selector[i].xpath(
               './p[@class="price"]/span[@class="search_now_price"]/text()').extract()
           date = selector[i].xpath('./p[@class="search_book_author"]/span[2]/text()').extract()
           detail = selector[i].xpath('./p[1]/a[1]/@title').extract()
      
    • 3 在pipelines文件中保存数据到sqlsever数据库

      • 3.1 首先删除同名表,然后创建新表
          def DBinit():
               try:
                    ##连接数据库 user用户名password密码database数据库名
                    con = pymssql.connect(host='localhost', user='lzx', password='lzx', database='lzx_')
                    cursor = con.cursor()
                    ##删除表
                   cursor.execute('drop table book')
                   con.commit()
               except Exception as ex:
                    print(ex)
               try:
                  ##创建表,由于字段信息的长度差距极大,故都设置为500长度
                   cursor.execute(
                       "create table book (id varchar(500),bTitle varchar(500),bAuthor varchar(500),bPublish varchar(500),"
                       "bDate varchar(500),bPrice varchar(500),bDetail varchar(500))")
                   ##提交并关闭
                   con.commit()
                   con.close()
               except Exception as ex:
                    print(ex)
        
      • 3.2 在DangdangSpiderPipeline类中根据item数据执行sqlserver插入语句
           def process_item(self, item, spider):
               try:
                   #链接数据库
                   self.con = pymssql.connect(host='localhost', user='lzx', password='lzx', database='lzx_')
                   self.cursor = self.con.cursor()
                   ##插入数据
                   self.cursor.execute("INSERT INTO book(id, bTitle,  bAuthor,bPublish,bDate, bPrice,bDetail) 
                   VALUES  ('%s','%s','%s','%s','%s','%s','%s')" % 
                   (item['id'],item['bTitle'],item['bAuthor'] ,item['bPublisher'] ,item['bDate'],item['bPrice'],item['bDetail'] ))
                   ##提交
                   self.con.commit()
                   print('已插入' + str(item['id']) + '行')
               except Exception as ex:
                   print(ex)
                return item
        
    • 4 settings设置

         BOT_NAME = 'dangdang_spider'
         SPIDER_MODULES = ['dangdang_spider.spiders']
         NEWSPIDER_MODULE = 'dangdang_spider.spiders'
         FEED_EXPORT_ENCODING = 'gb18030'
         ITEM_PIPELINES = {
             'dangdang_spider.pipelines.DangdangSpiderPipeline': 300,
         }
         HTTPERROR_ALLOWED_CODES = [301]
         DEFAULT_REQUEST_HEADERS={
         'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 >Safari/537.36'
         }
         ROBOTSTXT_OBEY = False
      
  • pycharm输出信息
  • 数据库保存结果

心得体会

  • 复现作业难度不大
    本次保存数据到本地sqlserver数据库,需要先删旧表才建新表
    scrapy是并发爬取多页的,所以爬取多页信息时id值会混乱,暂时不知道如何解决该问题
    由于图书信息如简介等存在缺失,所以不能直接爬取简介等标签信息,需要先xpath找到li节点,在对每个li节点进行xpath检索,否则会出现各字段长度
    不一致问题导致图书信息混淆

作业二

  • 要求
    熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;使用scrapy框架+Xpath+MySQL数据库存储技术路线爬取外汇网站数据。
  • 候选网站
    招商银行网:http://fx.cmbchina.com/hq/
  • 输出内容

结果展示

  • 思路:
    • 1 观察html源码,找到目标信息在//div[@id="realRateInfo"]/table/tr节点下

    • 2 根据子节点结构构建xpath搜索路径

        selector = selector.xpath('//div[@id="realRateInfo"]/table/tr')
        for i in range(1,len(selector)):
            ##根据路径提取信息 保存到item
            td=selector[i].xpath('./td')
            item['id'] = str(i)
            ##根据要求选择特定下标节点,同时去掉文本中的换行空格等字符
            item['Currency'] = td[0].xpath('./text()').extract()[0].\
                replace('\r','').replace('\n','').replace(' ','')
            item['TSP'] = td[3].xpath('./text()').extract()[0].\
                replace('\r','').replace('\n','').replace(' ','')
            item['CSP'] = td[4].xpath('./text()').extract()[0].\
                replace('\r','').replace('\n','').replace(' ','')
            item['TBP'] = td[5].xpath('./text()').extract()[0].\
                replace('\r','').replace('\n','').replace(' ','')
            item['CBP'] = td[6].xpath('./text()').extract()[0].\
                replace('\r','').replace('\n','').replace(' ','')
            item['Time'] = td[7].xpath('./text()').extract()[0].\
                replace('\r','').replace('\n','').replace(' ','')
      
      
    • 3 在pipelines文件中保存数据到sqlsever数据库的rate表

      • 3.1 首先删除同名表,然后创建新表
          def DBinit():
               try:
                    ##连接数据库 user用户名password密码database数据库名
                    con = pymssql.connect(host='localhost', user='lzx', password='lzx', database='lzx_')
                    cursor = con.cursor()
                    ##删除表
                   cursor.execute('drop table rate')
                   con.commit()
               except Exception as ex:
                    print(ex)
               try:
                  ##创建表
                   cursor.execute(
                       "create table rate (id varchar(20),Currency varchar(20),TSP varchar(20),CSP varchar(20),"
                       "TBP varchar(20),CBP varchar(20),Time varchar(20))")
                   ##提交并关闭
                   con.commit()
                   con.close()
               except Exception as ex:
                    print(ex)
        
      • 3.2 在DangdangSpiderPipeline类中根据item数据执行sqlserver插入语句
           def process_item(self, item, spider):
               try:
                   #链接数据库
                   self.con = pymssql.connect(host='localhost', user='lzx', password='lzx', database='lzx_')
                   self.cursor = self.con.cursor()
                   ##插入数据
                   self.cursor.execute("INSERT INTO rate(id, Currency,  TSP,CSP,TBP, CBP,Time) VALUES 
                    ('%s','%s','%s','%s','%s','%s','%s')" %
                   (item['id'], item['Currency'], item['TSP'], item['CSP'], item['TBP'], item['CBP'],item['Time']))
                   ##提交
                   self.con.commit()
                   print("_____________________________")
               except Exception as ex:
                   print(ex)
                return item
        
    • 4 settings设置

        BOT_NAME = 'zhaoshang_spider'
         SPIDER_MODULES = ['zhaoshang_spider.spiders']
        NEWSPIDER_MODULE = 'zhaoshang_spider.spiders'
         FEED_EXPORT_ENCODING = 'gb18030'
        ITEM_PIPELINES = {
            'zhaoshang_spider.pipelines.ZhaoshangSpiderPipeline': 300,
        }
        HTTPERROR_ALLOWED_CODES = [301]
        DEFAULT_REQUEST_HEADERS={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 > 
          Safari/537.36'
         }
         ROBOTSTXT_OBEY = False
      

心得体会

  • 和第一题一样
    不用翻页没有id混乱问题

作业三

  • 要求
    熟练掌握 Selenium 查找HTML元素、爬取Ajax网页数据、等待HTML元素等内容;
    使用Selenium框架+ MySQL数据库存储技术路线爬取“沪深A股”、“上证A股”、“深证A股”3个板块的股票数据信息。
  • 候选网址
    东方财富网:http://quote.eastmoney.com/center/gridlist.html#hs_a_board
  • 输出内容

结果展示

  • 思路
    • 1.检查网页元素,发现每条股票信息对应tbody标签下的每个子节点tr

      • 于是可以得到获取股票信息的xpath路径,代码如下:
      selector = scrapy.Selector(text=data)  ##selector选择器
      ##先获取一个页面下所有tr标签
      tr = selector.xpath(
          "/html/body/div[@class='page-wrapper']/div[@id='page-body']/div[@id='body- 
      main']/div[@id='table_wrapper']/div[@class='listview full']/table[@id='table_wrapper-table']/tbody/tr")
      ##获取tr标签下的对应信息提交给item
      for i in tr :
          id = i.xpath('./td[1]/text()').extract()
          bStockNo = i.xpath('./td[2]/a/text()').extract()
          bName = i.xpath('./td[3]/a/text()').extract()
          bLatestquo = i.xpath('./td[5]/span/text()').extract()
          bFluctuation = i.xpath('./td[6]/span/text()').extract()
          bTurnovernum = i.xpath('./td[8]/text()').extract()
          bTurnoveprice = i.xpath('./td[9]/text()').extract()
          bAmplitude = i.xpath('./td[10]/text()').extract()
          bHighest = i.xpath('./td[11]/span/text()').extract()
          bLowest = i.xpath('./td[12]/span/text()').extract()
          bToday = i.xpath('./td[13]/span/text()').extract()
          bYesterday = i.xpath('./td[14]/text()').extract()
      
    • 2.观察沪深A股,上证A股,深证A股的链接,发现对应的链接参数不同

      • 深证 =
        • 上证 =
          • 沪深 =
      • 根据url不同遍历每个板块
      • 一定要设置dont_filter为True否则scrapy会默认三种url相同然后去重,只会执行第一个页面请求
         def start_requests(self):
         ##遍历三个板块的url
             for i in ['hs','sh','sz']:
                 ##设置爬取页数:前四页
                 for j in range(4):
                     ##构造url
                     url='http://quote.eastmoney.com/center/gridlist.html#'+i+'_a_board'
                     ##注意一定要设置dont_filter=True,取消url去重
                     yield Request(url=url,callback=self.parse,dont_filter=True)
        
    • 3.观察板块网页发现,每页信息是动态加载的需要跳转页面后才会显示

      • 于是设置middlewares文件,设置selenium模拟输入页面跳转操作
          class DongfangSpiderDownloaderMiddleware:
              def __init__(self):
              self.driver = webdriver.Chrome()##启动浏览器
        
              def process_request(self, request, spider):
                global sum
                sum += 1##当前爬取页面数
                self.driver.get(request.url)##输入爬虫文件request的url
                time.sleep(2)##等待加载时间
                url = self.driver.current_url
                ##找到输入跳转页面数值框
                input=self.driver.find_element_by_xpath(
                "/html/body/div[@class='page-wrapper']/div[@id='page-body']/div[@id='body-
                main']/div[@id='table_wrapper']/div[@class='listview full']/div[@class='dataTables_wrapper']/div[@id='main-
                table_paginate']/input[@class='paginate_input']")
                ##找到确定跳转按钮
                submit=self.driver.find_element_by_xpath(
                "/html/body/div[@class='page-wrapper']/div[@id='page-body']/div[@id='body-
                main']/div[@id='table_wrapper']/div[@class='listview full']/div[@class='dataTables_wrapper']/div[@id='main-
                table_paginate']/a[@class='paginte_go']")
                input.clear()
                ##输入当前的爬取页面
                input.send_keys(sum)
                #确认提交
                submit.click()
                ##等待页面加载
                time.sleep(2)
                ##当sum达到4,即爬取完一个板块的前四页,重置sum为0
                if sum==4:
                  sum-=4
                ##获取网页信息
                source = self.driver.page_source
                response = HtmlResponse(url=url, body=source, encoding='utf-8')
                #提交截取的页面信息给爬虫文件
                return response
        
    • 4.最后设置settings文件

         BOT_NAME = 'dongfang_spider'
         SPIDER_MODULES = ['dongfang_spider.spiders']
         NEWSPIDER_MODULE = 'dongfang_spider.spiders'
         FEED_EXPORT_ENCODING = 'gb18030'
         HTTPERROR_ALLOWED_CODES = [301]
         DEFAULT_REQUEST_HEADERS={
         'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 > 
          Safari/537.36'
         }
         ITEM_PIPELINES = {  #启动管道
             'dongfang_spider.pipelines.DongfangSpiderPipeline': 300,
         }
         DOWNLOADER_MIDDLEWARES = {  #启动中间件
             'dongfang_spider.middlewares.DongfangSpiderDownloaderMiddleware': 543,
         }
         ROBOTSTXT_OBEY = False
      
    • 5.数据库操作类似前两题,不再赘述
      - 略

  • 结果
    • pycharm输出结果

    • 数据库截图

心得体会

  • 1.与前两题相比难点在于网页页面是动态加载的
  • 2.三个板块的url虽然不同但是scrapy会认定为相同,需要设置Scrapy.Request的dont_filter=True,否则只会爬取第一个板块页面请求,然后直接结束爬虫
  • 3.略微清楚了scrapy加selenium的爬取逻辑,爬虫文件先提交请求给中间件,然后中间件去模拟游览器操作,将操作完后得到的html源码发送给爬虫文件进行 回调函数操作

posted on 2021-11-20 08:32  linzeX  阅读(36)  评论(0编辑  收藏  举报

导航