Selenium快速入门

Selenium爬虫快速入门+案例spa2

引出
  • 对于有些网站来说,他的网页不是纯HTML标签加载出来的,而是用javascript渲染出来的,对于这样的网页,如果单纯的靠正则表达式、XPath来解析是行不通的。对于这样的网页,①是我们可以分析ajax请求,分析ajax参数发现其规律,自行模拟ajax请求(对于如何利用ajax参数爬取网页数据博主前面已经提到过),②是如果通过ajax参数无法发现其规律,我们可以利用selenium来模拟浏览器,说白了我们通过利用selenium和chrome driver就可以通过利用代码来模拟用户在浏览器上的各种交互了。

  • 在后文我会以 Scrape | Movie 中spa2 为例 分别演示两种方法

  • 作用

    • 便捷的获取网站动态加载的数据

    • 可以实现模拟登录

基本的使用(这里使用的 谷歌浏览器,后面我换成了火狐 )
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time
driver = webdriver.Chrome()
# 进入百度网站
driver.get('https://www.taobao.com')
# 通过find_element定位输入框
driver.find_element(By.ID,'q').send_keys('python')

btn=driver.find_element(By.CSS_SELECTOR,'.btn-search')
btn.click()

time.sleep(5)

1.动作链和切换Frame
如果定位的标签在iframe表中中必须采用以下操作
bro.switch_to.frame('')#切换浏览器定位的作用域

#动作链(实现拖拽)
from selenium.webdriver import ActionChains
action=ActionChains(bro)
click_and_hold(div):长按且点击操作
move_by_offset(x,y)
#第二种方法:
#获取目标以及源的位置 resource和target
ation.drag_and_drop(source,target)
perform()让动作链实现
action.release()

2.运行js代码
driver = webdriver.Chrome()
# 进入百度网站
driver.get('https://www.taobao.com')
# 通过find_element定位输入框
driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
driver.execute_script('alert("To Bottom")')
3.获取节点信息
data=driver.find_element(By.ID,'q')
获取属性值
data.get_attribute('src')
#获取文本值
data.text
获取id,位置,标签名和大小
data.id
data.location
data.tag_name
data.size

4.延时等待
隐式等待:
implicitly_wait()
显示等待:
	from selenium.webdriver.support import expected_conditions as EC
     selenium.webdriver.support.expected_conditions as EC ,可以对网页上元素是否存在,可点击等等进行判断,一般用于断言或与WebDriverWait配合使用。
    WebDriverWait中的until()和until_not()中的方法,必须是可调用的方法
    #visibility_of_all_elements_located()判断某个元素是不是不可访问或者不存在在DOM树中,不存在则返回True,存在则返回True,locator是一个元祖(by, path)
    locator=(By.CSS_SELECTOR,'div.el-card:nth-child(1) > div:nth-child(1) > div:nth-child(1) > div:nth-child(2) > a:nth-child(1)')
    el= wait.until(EC.visibility_of_all_elements_located(locator=locator))
    #print(bro.page_source)
5.cookie
bro.get_cookies()
cookie这里没有用到,就粗略的带过了,等用到了,我们再详细的讲解
6.反屏蔽
检测当前的浏览器窗口下的window.navigator对象是否包含webdriver这个属性,在正常访问下这个值为undefined,
         使用selenium就会给该值设置webdriver的属性,很多网站就会通过js判断,直接屏蔽
         解决方法:CDP开发工具协议  火狐不需要设置
         options.add_experimental_option('excludeSwitches', ['enable-automation'])
7.无头模式
 在案例运行的时候。浏览器总是跳来跳去的,看着很不舒服,这里使用无头模式,就不会弹出窗口,还可以提高速度
 options.add_argument("--headless") #设置火狐为headless无界面模式
 options.add_argument("--disable-gpu")	
spa2实战解析
方法一:是我们可以分析ajax请求,分析ajax参数发现其规律,自行模拟ajax请求
  • 这里我们可以发现这里是 动态渲染 每一个页面的后面都加了一个token
  • token的分析,就需要知道token是怎么算来的
  • 大致分析大致如下(我没有写的非常完整)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

import re
import requests
import urllib3
import pandas as pd
import json
import time
import hashlib
import base64
import random

urllib3.disable_warnings()

headers={
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.26'
}

def get_token():
    url='/api/movie'
    t = str(int(time.time()) - random.randint(1, 20))
    s = ','.join([url,'0', t])
    return base64.b64encode(','.join([hashlib.sha1(s.encode()).hexdigest(), t]).encode()).decode()


xxx=get_token()
url=f'https://spa2.scrape.center/api/movie/?limit=10&offset=0&token={xxx}'
response=requests.get(url,headers=headers,verify=False)
print(response.text)

第二种方法:利用selenium和chrome driver就可以通过利用代码来模拟用户在浏览器上的各种交互
1.分析过程
"""
from selenium.common.exceptions import TimeoutError
使用selenium来模拟浏览器,来实现spa2的实战
1.使用火狐浏览器
    需要下载火狐驱动器,并导入到当前文件
    firefox_options = Firefox_Options()
        #火狐浏览器.exe的位置
        firefox_options.binary = r"C:\Program Files\Mozilla Firefox\firefox.exe";
        #driver的位置
        s=Service(r"D:\code\mpvue\爬虫\aa\JavaScript的动态渲染页面爬取\Selenium的使用\Selenium\geckodriver.exe")
        bro = webdriver.Firefox(service=s,options=firefox_options)
2.怎么进行反屏蔽 以及 无头模式
    a:反屏蔽
         检测当前的浏览器窗口下的window.navigator对象是否包含webdriver这个属性,在正常访问下这个值为undefined,
         使用selenium就会给该值设置webdriver的属性,很多网站就会通过js判断,直接屏蔽
         解决方法:CDP开发工具协议  火狐不需要设置
         options.add_experimental_option('excludeSwitches', ['enable-automation'])
     b:无头模式
     options.add_argument("--headless") #设置火狐为headless无界面模式
	 options.add_argument("--disable-gpu")	
              
3.怎么判断一个列表页加载成功?
    selenium.webdriver.support.expected_conditions as EC ,可以对网页上元素是否存在,可点击等等进行判断,一般用于断言或与WebDriverWait配合使用。
    WebDriverWait中的until()和until_not()中的方法,必须是可调用的方法
    #visibility_of_all_elements_located()判断某个元素是不是不可访问或者不存在在DOM树中,不存在则返回True,存在则返回True,locator是一个元祖(by, path)
    locator=(By.CSS_SELECTOR,'div.el-card:nth-child(1) > div:nth-child(1) > div:nth-child(1) > div:nth-child(2) > a:nth-child(1)')
    el= wait.until(EC.visibility_of_all_elements_located(locator=locator))
    #print(bro.page_source)
4.怎么定位标签?
        a:
                元素对象 WebElement,是通过find_element方法获取的元素对象以及
                import By
                By.ID
                By.XPATH
                ....
                可以通过
                        .click()
                        .send_keys()
                        .clear()               
                        .text 获取文本
                        .get_property('value') 
                        .get_property('value') 
        首先这是一个动态渲染的页面,什么叫做动态渲染的页面,它就是先响应js获取数据,然后再将数据插入到html中,我们不能直接使用find_element直接去查找,
        因为这个时候,页面还没有完全加载出来,还需要等待额外的ajax请求,所以我们要使用延时等待, 判断页面是否加载完成  确保所有的节点加载出来。

5.存储方式
        a:json文本保存
          忽略
        
        b.csv方式保存
        
        c.MongDb存储
           忽略
        

url='https://spa2.scrape.center/page/2'
bro.get(url)

#3.判断页面是否加载成功
locator=(By.CSS_SELECTOR,'div.el-card:nth-child(1) > div:nth-child(1) > div:nth-child(1) > div:nth-child(2) > a:nth-child(1)')
el= wait.until(EC.visibility_of_all_elements_located(locator=locator))
#print(bro.page_source)
#定位标签


#/html/body/div/div[2]/div[1]/div[1]/div[3]/div/div/div[2]/a
#/html/body/div/div[2]/div[1]/div[1]/div[4]/div/div/div[2]/a

#/html/body/div/div[2]/div[1]/div[1]/div[1]/div/div/div[1]/a


links=[]
for i in range(1,11):
        xPth=r'/html/body/div/div[2]/div[1]/div[1]/div['+str(i)+']/div/div/div[2]/a'
        link=bro.find_element(By.XPATH,xPth).get_attribute('href')
        links.append(link)


url_1=links[0]
bro.get(url_1)
#判断详情页面是否加载完成
locator1=(By.TAG_NAME,'h2')
el= wait.until(EC.visibility_of_all_elements_located(locator=locator1))

name=bro.find_element(By.TAG_NAME,'h2').text
score=bro.find_element(By.CSS_SELECTOR,'.score').text
categories=bro.find_element(By.CSS_SELECTOR,'.categories').text
drama=bro.find_element(By.CSS_SELECTOR,'.drama > p:nth-child(2)').text

print(name)
        
        
以上细节讲解完毕,将相同方法抽取出来分装成函数

import logging
import time
import pprint
import csv
import pandas as pd
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options as options
from selenium.webdriver.firefox.options import Options as Firefox_Options
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait



#1.使用火狐浏览器 全局变量
options = Firefox_Options()
options.binary = r"C:\Program Files\Mozilla Firefox\firefox.exe";
options.add_argument("--headless") #设置火狐为headless无界面模式
options.add_argument("--disable-gpu")
s=Service(r"D:\code\mpvue\爬虫\aa\JavaScript的动态渲染页面爬取\Selenium的使用\Selenium\geckodriver.exe")
bro = webdriver.Firefox(service=s,options=options)
wait=WebDriverWait(bro,3)

"""
 url:要加载的页面
 condition:页面加载成功的判断条件---EC.visibility_of_all_elements_located
 locator:定位器
"""

def scrape_page(url, condition, locator):
        try:
                bro.get(url)
                wait.until(condition(locator))
        except TimeoutError:
                logging.ERROR(url + "该页面爬取错误")


"""
判断每一个index页面是否加载成功
"""


def scrape_index(page):
        url = f'https://spa2.scrape.center/page/' + str(page)
        scrape_page(url, condition=EC.visibility_of_all_elements_located, locator=(By.CSS_SELECTOR,
                                                                                   'div.el-card:nth-child(1) > div:nth-child(1) > div:nth-child(1) > div:nth-child(2) > a:nth-child(1)'))


"""
获取每一个index页面的links
"""


def parse_url():
        links = []
        for i in range(1, 11):
                xPth = r'/html/body/div/div[2]/div[1]/div[1]/div[' + str(i) + ']/div/div/div[2]/a'
                link = bro.find_element(By.XPATH, xPth).get_attribute('href')
                links.append(link)
        return links



def scrape_detail(url):
        name = bro.find_element(By.TAG_NAME, 'h2').text
        score = bro.find_element(By.CSS_SELECTOR, '.score').text
        categories = bro.find_element(By.CSS_SELECTOR, '.categories').text
        drama = bro.find_element(By.CSS_SELECTOR, '.drama > p:nth-child(2)').text
        data = {
                "链接": url,
                "电影名称": name,
                "电影类别": categories,
                "剧情": drama
        }
        return data

#5.a json方式保存

def writer_json(data_list):
        pass


#5.b  csv方式保存
def writer_csv(data_list):
        f=pd.DataFrame(data_list)
        f.to_csv('spa2.csv',index=['链接','电影名称','电影类别','剧情'])


if __name__ == '__main__':
        print("正在加载...........")
        data_list=[]
        for i in range(1, 11):
                scrape_index(i)
                url_list = parse_url()
                for url in url_list:
                        #判断页面是否加载完成
                        scrape_page(url, condition=EC.visibility_of_all_elements_located, locator=(By.TAG_NAME, 'h2'))
                        data=scrape_detail(url)
                        data_list.append(data)
        writer_csv(data_list)
        print("加载完成")

bro.close()


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值