爬虫入门(二)

1.selenium模块

(1)selenium模块简介
selenium是一个基于浏览器自动化的模块,可以便捷地获取动态加载的数据,便捷地实现模拟登录。
功能:
发起请求:get(url)
标签定位:find
标签交互:send_keys(‘xxx’)
执行js程序:excute_script(‘jscode’)
前进,后退:back(),forward()
关闭浏览器:quit()
(2)下载浏览器驱动(以chrome为例)
在chrome浏览器-帮助-关于google chrome中,可以看到chrome版本
在这里插入图片描述
在驱动下载链接 https://chromedriver.storage.googleapis.com/index.html中下载对应版本驱动
在这里插入图片描述
将exe程序放在如下目录下
在这里插入图片描述
定义一个selenium模块

from selenium import webdriver
bro=webdriver.Chrome(executable_path="../chromedriver/chromedriver")

(3)对于iframe的处理
以qq空间登陆界面为例,登录框是一个iframe子页面,使用selenium.find直接定位是定位不到的,所以需要先定位到iframe页面
在这里插入图片描述

#定位到iframe页面中
bro.switch_to.frame('login_frame')

(4)规避检测
一些网站会监测当前请求是否由selenium发出,需要规避检测

from selenium.webdriver import ChromeOptions
#实现规避检测
option=ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
bro=webdriver.Chrome(executable_path="../chromedriver/chromedriver",options=option)

(5)案例
登录qq空间
在登录qq的情况下,点击头像就可登录
在这里插入图片描述

from selenium import webdriver
from time import sleep
#规避检测
from selenium.webdriver import ChromeOptions

#实现规避检测
option=ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])

bro=webdriver.Chrome(executable_path="../chromedriver/chromedriver",options=option)

bro.get('https://qzone.qq.com/')
#定位到iframe页面中
bro.switch_to.frame('login_frame')
sleep(2)
btn=bro.find_element_by_id('')#引号内填img_out_qq号
sleep(2)
btn.click()

sleep(10)
bro.quit()

成功登录
在这里插入图片描述
登录12306(过滑块)

分别定位到用户名、密码和登录:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
点击“登录”,会弹出滑块,定位到滑块元素,使用动作链进行滑动。

在这里插入图片描述
滑动完成后成功登录。

在这里插入图片描述
代码:

from selenium import webdriver
from time import sleep
from selenium.webdriver import ChromeOptions
#定义动作链
from selenium.webdriver import ActionChains

#实现规避检测
option=ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])

bro=webdriver.Chrome(executable_path='../chromedriver/chromedriver',options=option)
bro.get('https://kyfw.12306.cn/otn/resources/login.html')
sleep(2.1)
username=bro.find_element_by_id('J-userName')
username.send_keys('')#引号内填账户名
sleep(1.2)
password=bro.find_element_by_id('J-password')
password.send_keys('')#引号内填密码
sleep(3.1)
login=bro.find_element_by_id('J-login')
login.click()
# 设置没有webdriver属性,避免被检测
script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
bro.execute_script(script)
sleep(3.2)
slider=bro.find_element_by_id('nc_1_n1z')
action=ActionChains(bro)
action.click_and_hold(slider)
action.move_by_offset(300,0).perform()

action.release()

二、scrapy框架

1.模块安装

pip install wheel
pip install pywin32
pip install scrapy

2.在终端输入指令创建一个工程,假设工程名命名为firstBlood

scrapy startproject firstBlood

创建工程后目录如下
在这里插入图片描述
3.进入firstBlood目录,在终端输入指令在spiders中创建一个爬虫文件,假设文件命名为first

cd firstBlood
scrapy genspider first www.xxx.com

创建爬虫文件后目录如下
在这里插入图片描述
4.持久化存储数据
(1)基于终端
局限性:只可将parse文件的返回值存储到本地的文本文件中,存储的文件类型只能为json、jsonlines、jl、csv、xml等;
指令:scrapy crawl xxx -o filepath
好处:简洁高效

【案例】爬取百度热搜标题存储到csv文件

在这里插入图片描述
first.py

import scrapy
import sys
sys.path.append(r'D:\pycharm_project\reptileStudy\code\scrapyProject\firstBlood\firstBlood')
import items

class FirstSpider(scrapy.Spider):
    #爬虫文件的名称,爬虫源文件的唯一标识
    name = 'first'
    #允许的域名,用来限定start_urls哪些可以进行请求发送
    #allowed_domains = ['http://scxk.nmpa.gov.cn:81/xk/']
    #起始的url列表,该列表中的url会被scrapy自动进行请求发送
    start_urls = ['http://www.baidu.com']

    #基于终端的持久化存储,只能存为固定的几种文件格式
    #用作数据解析,response参数是请求成功后对应的相应对象
    
    def parse(self, response):
        li_list=response.xpath('//ul[@class="s-hotsearch-content"]/li')
        #li_list=response.xpath('//ul[@id="gzlist"]/li[1]/dl/a/text()')
        print(li_list)
        all_data=[]
        for li in li_list:
            title=li.xpath('.//span[@class="title-content-title"]/text()')[0].extract()
            print(title)
            dic={
                "title":title
            }
            all_data.append(dic)

        return all_data

settings.py

BOT_NAME = 'firstBlood'

SPIDER_MODULES = ['firstBlood.spiders']
NEWSPIDER_MODULE = 'firstBlood.spiders'


# UA伪装
USER_AGENT = "'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'"
# Obey robots.txt rules,君子协议
ROBOTSTXT_OBEY = False

#只显示错误类型的信息
LOG_LEVEL='ERROR'
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
    'firstBlood.pipelines.FirstbloodPipeline': 300,#300表示的是优先级,数值越小优先级越高
}

在终端输入scrapy crawl first -o ../first.csv
爬取成功
在这里插入图片描述
在这里插入图片描述
(2)基于管道
编码流程:
数据解析,在item中定义相关的属性,把解析的数据存储到item类型的对象,把item类型的对象提交给管道的process_item函数进行持久化存储,在配置文件中开启管道。
好处:通用性强

【案例】将爬取的百度热搜题目存储到数据库
first.py

import scrapy
import sys
sys.path.append(r'D:\pycharm_project\reptileStudy\code\scrapyProject\firstBlood\firstBlood')
import items

class FirstSpider(scrapy.Spider):
    #爬虫文件的名称,爬虫源文件的唯一标识
    name = 'first'
    #允许的域名,用来限定start_urls哪些可以进行请求发送
    #allowed_domains = ['http://scxk.nmpa.gov.cn:81/xk/']
    #起始的url列表,该列表中的url会被scrapy自动进行请求发送
    start_urls = ['http://www.baidu.com']
    #基于管道的持久化存储
    def parse(self, response):
        li_list=response.xpath('//ul[@class="s-hotsearch-content"]/li')
        #li_list=response.xpath('//ul[@id="gzlist"]/li[1]/dl/a/text()')
        print(li_list)
        all_data=[]
        count=0
        for li in li_list:
            count = count + 1
            title=li.xpath('.//span[@class="title-content-title"]/text()')[0].extract()
            print(count)
            print(title)
            item=items.FirstbloodItem()
            item['title']=title
            item['count']=count
            yield item

items.py

import scrapy


class FirstbloodItem(scrapy.Item):
    # define the fields for your item here like:
    title = scrapy.Field()
    count = scrapy.Field()
    pass

pipelines.py

import pymysql

class FirstbloodPipeline:
    fp=None
    #重写父类的一个方法,该方法只在开始爬虫时被调用一次
    def open_spider(self,spider):
        print('开始爬虫---')
        self.fp=open('../first.txt','w',encoding='utf-8')
    #接收爬虫文件提交过来的item对象
    #该方法每接收到一个item就会被调用一次
    def process_item(self, item, spider):
        title=item['title']
        count=item['count']
        self.fp.write(title+'\n')
        return item  #传递给下一个即将被执行的管道类
    def close_spider(self,spider):
        print('结束爬虫---')
        self.fp.close()
#管道文件中一个管道类对应将一组数据存储到一个平台或载体中
class mysqlPipeLine(object):
    conn=None
    cursor=None
    def open_spider(self,spider):
        self.conn=pymysql.connect(host='127.0.0.1',port=3306,user='root',password='123456',db='sakila')

    def process_item(self,item,spider):
        self.cursor = self.conn.cursor()
        try:
            self.cursor.execute(f'insert into baidutitle values("{item["count"]}","{item["title"]}")')
            self.conn.commit()
        except Exception as e:
            print(e)
            self.conn.rollback()
        return item
    def close_spider(self,spider):
        self.cursor.close()
        self.conn.close()

settings.py

BOT_NAME = 'firstBlood'

SPIDER_MODULES = ['firstBlood.spiders']
NEWSPIDER_MODULE = 'firstBlood.spiders'


# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = "'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'"

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

#只显示错误类型的信息
LOG_LEVEL='ERROR'
ITEM_PIPELINES = {
    'firstBlood.pipelines.FirstbloodPipeline': 300,#300表示的是优先级,数值越小优先级越高
    'firstBlood.pipelines.mysqlPipeLine': 301
}

在终端输入scrapy crawl first
在这里插入图片描述
查看数据库
在这里插入图片描述
成功爬取。

5.管道存储图片(scrapy.pipelines.images)

4是用来存储文本,若存储图片,可以用scrapy.pipelines.images。
步骤:
1.对图片地址进行数据解析;
2.把item提交到管道;
3.在管道中定制一个基于scrapy.pipelines.images的管道类;
4.在配置文件中开启管道类,设置为自定义的管道;设置图片存储地址。

【案例】爬取学习通PPT
在这里插入图片描述

如图所示,学习通课程内嵌的PPT无法整个下载,它是由一张张图片组成,若想保存需要逐张另存,工作量很大。我们可以通过请求图片链接进行批量下载。

步骤

(1)定位到PPT所在子页面,可以看到它属于一个iframe,这个iframe有一个链接。
在这里插入图片描述
但链接只是一部分,我们需要在这个链接前拼接https://mooc1-2.chaoxing.com/,才是完整链接。
在这里插入图片描述
(2)进入拼接后的网址,如上图。发现这里面PPT还是在一个子页面中,再次检查这一页的iframe地址。
在这里插入图片描述
可以看到这个iframe中的src是完整的,直接访问这个src所对应的网页。
(3)访问后,该网页中看到的就是一张张图片,每张图片对应一个链接,爬虫对这些链接发送request请求,则可以下载。
在这里插入图片描述
代码

结构目录
在这里插入图片描述

second.py

import scrapy
import sys
sys.path.append(r'D:\pycharm_project\reptileStudy\code\scrapyProject\secondBlood\secondBlood')
import items

class SecondSpider(scrapy.Spider):
    name = 'second'
    allowed_domains = ['www.xxx.com']
    start_urls = ['https://pan-yz.chaoxing.com/screen/file_5807583ce09b9083dbb4809301792d4b?ext=%7B%22_from_%22%3A%22221688283_48606782_57041418_6ac69e101569e5992d151553e49dd379%22%7D']

    def parse(self, response):
        img_list=response.xpath("/html/body/div[1]/img")
        count=1
        for img in img_list:
            item = items.SecondbloodItem()
            img_url=img.xpath('./@src')[0].extract()
            item['img']=img_url
            item['name']=str(count)+'.png'
            count=count+1
            yield item

pipelines.py

from scrapy.pipelines.images import ImagesPipeline
import scrapy

class imgsPipeLine(ImagesPipeline):
    #请求图片
    def get_media_requests(self,item,info):
        yield scrapy.Request(item['img'])
    #指定存储路径
    def file_path(self, request, response=None, info=None, *, item=None):
        imgname=item['name']
        return imgname

    #把item返回给下一个被执行的管道类
    def item_completed(self, results, item, info):
        return item

settings.py

BOT_NAME = 'secondBlood'

SPIDER_MODULES = ['secondBlood.spiders']
NEWSPIDER_MODULE = 'secondBlood.spiders'

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = "User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"

# Obey robots.txt rules
ROBOTSTXT_OBEY = False
LOG_LEVEL = 'ERROR'
IMAGES_STORE='../images'
ITEM_PIPELINES = {
    'secondBlood.pipelines.imgsPipeLine': 300, #要执行的管道类,自定义类后一定要更换
}

items.py

import scrapy


class SecondbloodItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    img=scrapy.Field()
    name=scrapy.Field()
    pass

在pycharm终端的scrapyProject\secondBlood路径下,输入scrapy crawl second执行
图片已存在images文件夹下:
在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值