当前位置: 代码迷 >> 综合 >> selenium+phantomjs/chrome/firefox 的操作(八)
  详细解决方案

selenium+phantomjs/chrome/firefox 的操作(八)

热度:120   发布时间:2023-11-11 02:37:00.0

回顾(七)

selenium+phantomjs/chrome/firefox

  • 设置无界面模式(chromedriver | firefox)

    options = webdriver.ChromeOptions()
    options.add_argument('--headless')browser = webdriver.Chrome(options=options)
    browser.get(url)
    
  • browser执行JS脚本

    browser.execute_script(
    'window.scrollTo(0,document.body.scrollHeight)'
    )
    time.sleep(2)
    
  • selenium常用操作

    1】键盘操作from selenium.webdriver.common.keys import Keysnode.send_keys(Keys.SPACE)node.send_keys(Keys.CONTROL, 'a')node.send_keys(Keys.CONTROL, 'c')node.send_keys(Keys.CONTROL, 'v')node.send_keys(Keys.ENTER)2】鼠标操作from selenium.webdriver import ActionChainsmouse_action = ActionChains(browser)mouse_action.move_to_element(node)mouse_action.perform()3】切换句柄all_handles = browser.window_handlestime.sleep(1)browser.switch_to.window(all_handles[1])4】iframe子框架browser.switch_to.frame(iframe_element)# 写法1 - 任何场景都可以: iframe_node = browser.find_element_by_xpath('')browser.switch_to.frame(iframe_node)# 写法2 - 默认支持 id 和 name 两个属性值:browser.switch_to.frame('id属性值|name属性值')
    

scrapy框架

  • 五大组件

    1】引擎(Engine)----------整个框架核心
    【2】爬虫程序(Spider)------数据解析提取
    【3】调度器(Scheduler)-----维护请求队列
    【4】下载器(Downloader)----获取响应对象
    【5】管道文件(Pipeline)-----数据入库处理【两个中间件】下载器中间件(Downloader Middlewares)蜘蛛中间件(Spider Middlewares)
    
  • 工作流程

    1】Engine向Spider索要URL,交给Scheduler入队列
    【2】Scheduler处理后出队列,通过Downloader Middlewares交给Downloader去下载
    【3】Downloader得到响应后,通过Spider Middlewares交给Spider
    【4】Spider数据提取:4.1) 数据交给Pipeline处理4.2) 需要跟进URL,继续交给Scheduler入队列,依次循环
    
  • 常用命令

    1】创建爬虫项目 : scrapy startproject 项目名
    【2】创建爬虫文件2.1) cd 项目文件夹2.2) scrapy genspider 爬虫名 域名
    【3】运行爬虫scrapy crawl 爬虫名
    
  • scrapy项目目录结构

    Baidu                   # 项目文件夹
    ├── Baidu               # 项目目录
    │   ├── items.py        # 定义数据结构
    │   ├── middlewares.py  # 中间件
    │   ├── pipelines.py    # 数据处理
    │   ├── settings.py     # 全局配置
    │   └── spiders
    │       ├── baidu.py    # 爬虫文件
    └── scrapy.cfg          # 项目基本配置文件
    

scrapy(八)

scrapy框架

  • 全局配置文件settings.py详解

    1】定义User-AgentUSER_AGENT = 'Mozilla/5.0'2】是否遵循robots协议,一般设置为FalseROBOTSTXT_OBEY = 'False'3】最大并发量,默认为16CONCURRENT_REQUESTS = 324】下载延迟时间DOWNLOAD_DELAY = 15】请求头,此处也可以添加User-AgentDEFAULT_REQUEST_HEADERS = {
          }
    
  • 创建爬虫项目步骤

    1】新建项目 :scrapy startproject 项目名
    【2】cd 项目文件夹
    【3】新建爬虫文件 :scrapy genspider 文件名 域名
    【4】明确目标(items.py)5】写爬虫程序(文件名.py)6】管道文件(pipelines.py)7】全局配置(settings.py)8】运行爬虫8.1) 终端: scrapy crawl 爬虫名8.2) pycharm运行a> 创建run.py(和scrapy.cfg文件同目录)from scrapy import cmdlinecmdline.execute('scrapy crawl maoyan'.split())b> 直接运行 run.py 即可
    

还记得我们抓取的 百度一下,你就知道 吗

  • 步骤跟踪

    1】创建项目 'Baidu' 和爬虫文件 'baidu'1.1) scrapy startproject Baidu1.2) cd Baidu1.3) scrapy genspider baidu www.baidu.com【2】打开爬虫文件: baidu.pyimport scrapyclass BaiduSpider(scarpy.Spider):name = 'baidu'allowed_domains = ['www.baidu.com']start_urls = ['http://www.baidu.com/']def parse(self,response):r_list = response.xpath('/html/head/title/text()').extract()print(r_list)3】全局配置文件: settings.pyROBOTSTXT_OBEY = FalseDEFAULT_REQUEST_HEADERS = {
          'User-Agent':'Mozilla/5.0'}4】创建文件(和项目目录同路径): run.pyfrom scrapy import cmdlinecmdline.execute('scrapy crawl baidu'.split())5】运行 run.py 启动爬虫
    
    • scrapy写爬虫步骤

      1】items.py 定义抓取的数据结构: name=scrapy.Field()2】spider.py 开始进行数据抓取,通过如下3行代码交给管道from ..items import XxxItemitem = XxxItem()yield item
      【3】pipelines.py中开始处理数据
      【4】settings.py中开启管道ITEM_PIPELINES = {
              'Xxx.pipelines.XxxPipeline':200}
      

    瓜子二手车直卖网

  • 目标

1】抓取瓜子二手车官网二手车收据(我要买车)【2】URL地址:https://www.guazi.com/langfang/buy/o{
    }/#breadURL规律: o1  o2  o3  o4  o5  ... ...3】所抓数据3.1) 汽车链接3.2) 汽车名称3.3) 汽车价格

实现步骤

  • 1-创建项目和爬虫文件

    scrapy startproject Car
    cd Car
    scrapy genspider car www.guazi.com
    
  • 2-定义要爬取的数据结构

    """items.py"""
    import scrapyclass CarItem(scrapy.Item):# 链接、名称、价格url = scrapy.Field()name = scrapy.Field()price = scrapy.Field()
    
  • 3-编写爬虫文件(代码实现1)

    """ 此方法其实还是一页一页抓取,效率并没有提升,和单线程一样xpath表达式如下: 【1】基准xpath,匹配所有汽车节点对象列表li_list = response.xpath('//ul[@class="carlist clearfix js-top"]/li')【2】遍历后每辆车信息的xpath表达式汽车链接: './a[1]/@href'汽车名称: './/h2[@class="t"]/text()'汽车价格: './/div[@class="t-price"]/p/text()' """
    # -*- coding: utf-8 -*-
    import scrapy
    from ..items import CarItemclass CarSpider(scrapy.Spider):name = 'car'allowed_domains = ['www.guazi.com']i = 1start_urls = ['https://www.guazi.com/langfang/buy/o1/']def parse(self, response):# 1.基准xpath,匹配所有汽车节点对象列表li_list = response.xpath('//ul[@class="carlist clearfix js-top"]/li')# 创建item对象,给items.py中定义的数据结构赋值item = CarItem()for li in li_list:item['url'] = 'https://www.guazi.com/' + li.xpath('./a[1]/@href').get()item['name'] = li.xpath('.//h2[@class="t"]/text()').get()item['price'] = li.xpath('.//div[@class="t-price"]/p/text()').get()yield item# 生成下一页的链接,继续交给调度器入队列if self.i < 5:self.i += 1url = 'https://www.guazi.com/langfang/buy/o{}/'.format(self.i)# scrapy.Request()是将请求交给调度器入队列的方法yield scrapy.Request(url=url,callback=self.parse)
    
  • 3-编写爬虫文件(代码实现2)

    """ 重写start_requests()方法,效率极高 """
    # -*- coding: utf-8 -*-
    import scrapy
    from ..items import CarItemclass CarSpider(scrapy.Spider):name = 'car2'allowed_domains = ['www.guazi.com']# 1、去掉 start_urls# 2、重写start_requests()方法def start_requests(self):"""生成所有待爬取的URL地址,统一交给调度器入队列"""for i in range(1,5):url = 'https://www.guazi.com/langfang/buy/o{}/'.format(i)yield scrapy.Request(url=url,callback=self.parse)def parse(self, response):# 1.基准xpath,匹配所有汽车节点对象列表li_list = response.xpath('//ul[@class="carlist clearfix js-top"]/li')# 创建item对象,给items.py中定义的数据结构赋值item = CarItem()for li in li_list:item['url'] = 'https://www.guazi.com/' + li.xpath('./a[1]/@href').get()item['name'] = li.xpath('.//h2[@class="t"]/text()').get()item['price'] = li.xpath('.//div[@class="t-price"]/p/text()').get()yield item
    
  • 4-管道文件处理数据

    """ pipelines.py处理数据 1、mysql数据库建库建表 create database guazidb charset utf8; use guazidb; create table guazitab( name varchar(200), price varchar(100), url varchar(500) )charset=utf8; """
    # -*- coding: utf-8 -*-# 管道1 - 从终端打印输出
    class CarPipeline(object):def process_item(self, item, spider):print(item['name'],item['price'],item['url'])return item# 管道2 - 存入MySQL数据库管道
    import pymysql
    from .settings import *class CarMysqlPipeline(object):def open_spider(self,spider):"""爬虫项目启动时只执行1次,一般用于数据库连接"""self.db = pymysql.connect(MYSQL_HOST,MYSQL_USER,MYSQL_PWD,MYSQL_DB,charset=CHARSET)self.cursor = self.db.cursor()def process_item(self,item,spider):"""处理从爬虫文件传过来的item数据"""ins = 'insert into guazitab values(%s,%s,%s)'car_li = [item['name'],item['price'],item['url']]self.cursor.execute(ins,car_li)self.db.commit()return itemdef close_spider(self,spider):"""爬虫程序结束时只执行1次,一般用于数据库断开"""self.cursor.close()self.db.close()# 管道3 - 存入MongoDB管道
    import pymongoclass CarMongoPipeline(object):def open_spider(self,spider):self.conn = pymongo.MongoClient(MONGO_HOST,MONGO_PORT)self.db = self.conn[MONGO_DB]self.myset = self.db[MONGO_SET]def process_item(self,item,spider):car_dict = {
          'name' : item['name'],'price': item['price'],'url'  : item['url']}self.myset.insert_one(car_dict)
    
  • 5-全局配置文件(settings.py)

    1】ROBOTSTXT_OBEY = False2】DOWNLOAD_DELAY = 23】COOKIES_ENABLED = False4】DEFAULT_REQUEST_HEADERS = {
          "Cookie": "此处填写抓包抓取到的Cookie","User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36",}5】ITEM_PIPELINES = {
          'Car.pipelines.CarPipeline': 300,#'Car.pipelines.CarMysqlPipeline': 400,#'Car.pipelines.CarMongoPipeline': 500,}6】定义MySQL相关变量
    MYSQL_HOST = 'localhost'
    MYSQL_USER = 'root'
    MYSQL_PWD = '123456'
    MYSQL_DB = 'guazidb'
    CHARSET = 'utf8'7】定义MongoDB相关变量
    MONGO_HOST = 'localhost'
    MONGO_PORT = 27017
    MONGO_DB = 'guazidb'
    MONGO_SET = 'guaziset'
    
  • 6-运行爬虫(run.py)

    """run.py"""
    from scrapy import cmdline
    cmdline.execute('scrapy crawl maoyan'.split())
    

数据持久化(MySQL)

  • 实现步骤

    1】在setting.py中定义相关变量【2】pipelines.py中导入settings模块def open_spider(self,spider):"""爬虫开始执行1次,用于数据库连接"""def process_item(self,item,spider):"""具体处理数据"""return item def close_spider(self,spider):"""爬虫结束时执行1次,用于断开数据库连接"""3】settings.py中添加此管道ITEM_PIPELINES = {
          '':200}【注意】 :process_item() 函数中一定要 return item ,当前管道的process_item()的返回值会作为下一个管道 process_item()的参数
    

知识点汇总

  • 节点对象.xpath(’’)

    1】列表,元素为选择器 [<selector xpath='xxx' data='A'>,<selector xpath='xxx' data='B'>]2】列表.extract() :序列化列表中所有选择器为Unicode字符串 ['A','B']3】列表.extract_first() 或者 get() :获取列表中第1个序列化的元素(字符串) 'A'
    
  • 日志变量及日志级别(settings.py)

    # 日志相关变量 - settings.py
    LOG_LEVEL = ''
    LOG_FILE = '文件名.log'# 日志级别
    5 CRITICAL :严重错误
    4 ERROR    :普通错误
    3 WARNING  :警告
    2 INFO     :一般信息
    1 DEBUG    :调试信息
    # 注意: 只显示当前级别的日志和比当前级别日志更严重的
    
  • 管道文件使用

    1】在爬虫文件中为items.py中类做实例化,用爬下来的数据给对象赋值from ..items import MaoyanItemitem = MaoyanItem()2】管道文件(pipelines.py)【3】开启管道(settings.py)ITEM_PIPELINES = {
           '项目目录名.pipelines.类名':优先级 }
    

保存为csv、json文件

  • 命令格式

    """run.py"""1】存入csv文件scrapy crawl car -o car.csv【2】存入json文件scrapy crawl car -o car.json【3】注意: settings.py中设置导出编码 - 主要针对json文件FEED_EXPORT_ENCODING = 'utf-8'
    
  • 课堂练习

    【熟悉整个流程】 : 将猫眼电影案例数据抓取,存入MySQL数据库
    

新浪新闻全站抓取

  • 目标

    1】抓取新浪新闻下的所有分类的所有新闻,保存到本地
    【2】URL: 新浪官网 - 更多 - 导航  http://news.sina.com.cn/guide/3】要求将信息保存到scrapy项目目录的 data 文件夹中,并按照分类名称创建子文件夹
    

实现步骤

  • 1-创建项目和爬虫文件

    scrapy startproject Sina
    cd Sina
    scrapy genspider sina news.sina.com.cn
    
  • 2-定义要抓取的数据结构

    """items.py"""
    import scrapyclass SinaItem(scrapy.Item):# 大类标题、url 例:新闻、体育、娱乐、财经... ...parent_name = scrapy.Field()parent_url = scrapy.Field()# 小类标题、url 例: 体育分类下的 NBA CBA ... ...son_name = scrapy.Field()son_url = scrapy.Field()# 小类目录存储路径son_filename = scrapy.Field()# 小类下的文章链接、标题、内容article_url = scrapy.Field()article_head = scrapy.Field()article_content = scrapy.Field()
    
  • 3-爬虫文件进行数据解析提取

    """sina.py"""
    # -*- coding: utf-8 -*-
    import scrapy
    import os
    from ..items import SinaItemclass SinaSpider(scrapy.Spider):name = 'sina'allowed_domains = ['sina.com.cn']# 起始URL地址为导航页的地址start_urls = ['http://news.sina.com.cn/guide/']def parse(self, response):# 用来存放下一次交给调度器的所有请求,即所有小分类的请求son_items = []# 基准xpath:获取所有大分类的对象列表div_list = response.xpath('//div[@id="tab01"]/div')for div in div_list:# 1个大分类名称parent_name = div.xpath('./h3/a/text()').get()parent_url = div.xpath('./h3/a/@href').get()if parent_name and parent_url:# 1个大分类下面的所有小分类li_list = div.xpath('./ul/li')for li in li_list:# 继续交给调度器的item对象,确保每个是独立的item = SinaItem()item['son_name'] = li.xpath('./a/text()').get()item['son_url'] = li.xpath('./a/@href').get()item['parent_name'] = parent_nameitem['parent_url'] = parent_url# 创建对应的文件夹directory = './data/{}/{}/'.format(item['parent_name'],item['son_name'])item['son_filename'] = directoryif not os.path.exists(directory):os.makedirs(directory)son_items.append(item)# 大循环结束,items中存放了所有的每个小类请求的 item 对象# 发送每个请求到调度器,得到response连同meta数据一起回调函数parse_son_url方法for item in son_items:yield scrapy.Request(url=item['son_url'],meta={
          'meta_1':item},callback=self.parse_son_url)def parse_son_url(self,response):"""解析小分类函数"""meta1_item = response.meta['meta_1']# 存放所有新闻页链接的item请求列表meta1_items = []parent_url = meta1_item['parent_url']# 通过观察规律,小分类中的所有新闻连接均以最外层大链接开头news_link_list = response.xpath('//a/@href').extract()for news_link in news_link_list:if news_link.startswith(parent_url) and news_link.endswith('.shtml'):# 此item对象是需要继续交给调度器入队列的请求item = SinaItem()# 把具体的新闻链接发送请求,保存到对应的文件夹下item['son_name'] = meta1_item['son_name']item['son_url'] = meta1_item['son_url']item['parent_name'] = meta1_item['parent_name']item['parent_url'] = meta1_item['parent_url']item['son_filename'] = meta1_item['son_filename']item['article_url'] = news_linkmeta1_items.append(item)# 发送每个小类下的新闻链接请求,得到response后和meta数据交给get_content()函数处理for item in meta1_items:yield scrapy.Request(url=item['article_url'], meta={
          'meta_2': item}, callback=self.get_content)def get_content(self,response):"""获取每个新闻的具体内容"""item = response.meta['meta_2']item['article_head'] = response.xpath('//h1[@class="main-title"]/text() | //span[@class="location"]/h1/text()').get()item['article_content'] = '\n'.join(response.xpath('//div[@class="article"]/p/text() | //div[@class="article clearfix"]/p/text() | //div[@id="artibody"]/p/text()').extract())yield item
    
  • 4-数据处理

    """pipelines.py"""
    # -*- coding: utf-8 -*-class SinaPipeline(object):def process_item(self, item, spider):# 文件名使用url地址的中间(即去掉协议和后缀.shtml)filename = item['article_url'][7:-6].replace('/','-')filename_ = item['son_filename'] + filename + '.txt'# 写入本地文件with open(filename_,'w',encoding='utf-8') as f:f.write(item['article_content'])return item
    
  • 5-全局配置

    """settings.py"""
    ROBOTSTXT_OBEY = False
    DOWNLOAD_DELAY = 1
    DEFAULT_REQUEST_HEADERS = {
          'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8','Accept-Language': 'en','User-Agent': 'Mozilla/5.0',
    }
    ITEM_PIPELINES = {
          'Sina.pipelines.SinaPipeline': 300,
    }
    
  • 6-运行爬虫

    """run.py"""
    from scrapy import cmdline
    cmdline.execute('scrapy crawl sina'.split())
    

今日作业(九里面会有答案哦)

1】scrapy框架有哪几大组件?以及各个组件之间是如何工作的?【2】腾讯招聘尝试改写为scrapy2.1) response.text :获取页面响应内容2.2) scrapy中同样可以使用之前学过的模块,比如果 json模块 等【3】盗墓笔记小说抓取3.1) 目标: 抓取盗墓笔记1-8中所有章节的所有小说的具体内容,保存到本地文件3.2) http://www.daomubiji.com/3.3) 保存路径示例: ./novel/盗墓笔记1:七星鲁王宫/七星鲁王_第一章_血尸.txt./novel/盗墓笔记1:七星鲁王宫/七星鲁王_第二章_五十年后.txt
  • 盗墓笔记作业提示

    1】一级页面xpath表达式:a节点: //li[contains(@id,"menu-item-20")]/atitle: ./text()link : ./@href【2】二级页面xpath表达式基准xpath ://articlefor循环遍历后:name=article.xpath('./a/text()').get()link=article.xpath('./a/@href').get()3】三级页面xpath:response.xpath('//article[@class="article-content"]/p/text()').extract()# 结果: ['p1','p2','p3','']
    
  相关解决方案