0


【python爬虫一】爬虫基础操作

爬虫概述

  • 概念:是一种按照一定的规则,自动地抓取互联网上网页中相应信息(文本、图片等)的程序或脚本,然后把抓取的信息存储下来。

爬虫的分类

  • 通用爬虫:把一整张页面源码数据进行爬取
  • 聚焦爬虫:把页面中指定的数据进行爬取
  • 增量式爬虫:监测网站数据更新的情况。
  • 分布式爬虫:基于联合且分布的形式快速进行数据爬取
  • 功能爬虫:刷评论,点赞等功能

反爬机制

作用在web的服务端。制定相关的机制来阻止爬虫对其网站数据的爬取。

  • rebots 协议: 仅仅声明了门户端的哪些数据可被爬,哪些不可被爬。

反反爬机制

作用在爬虫,破解反爬机制。

requests 基础操作

  • requests 是一个基于网络请求的模块。用来模拟浏览器发请求。
import requests

url ='https://www.sogou.com/'# 发起get请求
response = requests.get(url=url)
page_text = response.text
withopen('./sogou.html','w', encoding='utf-8')as fp:
    fp.write(page_text)

User-Agent

设置

headers ={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'}
url ='https://www.sogou.com/web?query=杭州'
response = requests.get(url=url, headers=headers)
page_text = response.text
withopen('./hang.html','w', encoding='utf-8')as fp:
    fp.write(page_text)# params 参数
wd =input("enter a keyword:")
params ={'query': wd}
url ='https://www.sogou.com/web'
response = requests.get(url=url, headers=headers, params=params)# 参数动态化
page_text = response.text

# 响应数据为json 则
page_info = response.json()

发送post请求

headers ={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'}
url ='https://www.sogou.com/web?query=杭州'
data ={'page':1,'pageSize':10}
response = requests.post(url=url, headers=headers, data=data)
page_text = response.json()# 参数为json形式
data ={'page':1,'pageSize':10}
requests.post(url=url, headers=headers, json=data)

urllib 基于网络请求的模块

# 基于requests 的图片爬取import requests

headers ={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'}
img_data = requests.get("https://lmg.jj20.com/up/allimg/tp03/1Z9221U602IE-0-lp.jpg", headers=headers).content # content 返回bytes类型的数据withopen('./123.jpg','wb')as f:
    f.write(img_data)# 基于urllib的图片爬取from urllib import request

request.urlretrieve("https://lmg.jj20.com/up/allimg/tp03/1Z9221U602IE-0-lp.jpg",'./234.jpg')

html 数据解析

bs4

基本使用

  • 环境安装
pip install bs4 lxml
  • bs4实现解析的流程: - 实例化一个BeautifulSoup的对象,需要把即将解析的页面源码数据加载到该对象中。- 调用BeautifulSoup对象中相关的属性和方法进行标签定位和数据的提取
  • BeautifulSoup对象的实例化 1. BeautifulSoup(fp, 'lxml') 可以将fp表示的一个文件中的数据进行解析操作2. BeautifulSoup(page_text, 'lxml') 直接将请求到的页面源码数据进行解析操作
from bs4 import BeautifulSoup

fp =open('./test.html','r', encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')## 标签定位
soup.title # <title>document</title>## 属性定位
soup.find('div', class_='tang')# 返回str
soup.find_all('div', class_='tang')# 返回列表## 选择器定位
soup.select('#feng')#返回列表
soup.select('.tang>ul>li')# 返回列表## 取文本内容
div_tag = soup.select('.tang')[0]
div_tag.text

## 取属性
a_tag = soup.find('a',id='feng')
a_tag['href']

总结:
bs4的基本使用:

  • 标签定位: - soup.tagName: 只可以返回符合条件的第一个标签- soup.find('tagName', attrName='value'): 属性定位。返回值是匹配到的第一个元素- soup.find_all('tagName', attrName='value'): 返回匹配到的所以元素。返回列表- soup.select('css 选择器') : 返回列表
  • 数据提取: - 取标签中存储的数据 - string:只可以取出标签中直系的文本内容- text:可以取的标签中所有的文本- 取标签属性的数据 - tag['attrName']

xpath

解析

  • 解析流程: - 实例化一个etree对象,然后把即将被解析的数据加载到该对象中- 调用etree对象中的xpath方法结合着不同形式的xpath表达式进行标签定位和数据提取
  • etree对象的实例化 1. etree.parse(filePath)2. etree.HTML(page_text)
  • 标签定位 - 非最左侧的/:表示一个层级- 非最左侧的//:表示多个层级- 最左侧的/:必须从根节点开始进行标签定位(/html),表示绝对路径- 最左侧的//:可以从任意位置进行标签定位,表示相对路径 **重点- 属性定位的写法://tagName[@attrName="value"]- 索引定位://tagName[index] 索引是从1开始的
  • 数据提取 - 提取标签数据 - //text(): 返回标签下所有节点的数据。包含子节点的文本内容- /text():只可以返回直接子节点的文本内容- 提取属性数据 - /@attrName:获取指定属性的值。返回列表
from lxml import etree

tree = etree.parse('./test.html')# ElementTree 类型的对象
tree.xpath('/html/head/title')[0]
tree.xpath('/html//title')[0]
tree.xpath('//title')[0]

tree.xpath('//div[@class="song"]')
tree.xpath('//div[3]')## 数据提取
tree.xpath('a[@id="feng"]//text()')
tree.xpath('a[@id="feng"]/text()')

tree.xpath('a[@id="feng"]//@href')

案例

from lxml import etree

page_text = requests.get("https://www.qiushibaike.com/text/", headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'}).text

tree = etree.HTML(page_text)
div_list = tree.xpath('//*[@id="content"]/div/div[2]/div')
fot div in div_list:
    auther = div.xpath('./div[1]/a[2]/h2/text()')[0]# 局部解析xpath, . 表示当前div
    content = div.xpath('./a[1]/div/span//text()')
    content =''.join(content)print(auther, content)
  • xpath 管道符的使用 - 作用:可以使得xpath表达式具有更强的通用性- //div[1]/a/@href | //div[1]/p/a/@href

requests 高级操作

Cookie在爬虫中的应用

  • 手动处理cookie:直接将cookie放在请求头headers中
  • 自动处理:Session对象 - session的创建:requests.Session()- session可以和requests一样调用get和post进行请求发送。如果使用session进行请求发送,则服务端响应后产生的cookie会被自动存储到session对象中。第二次请求时,自动携带存储的cookie。(即:session对象至少要发送两次请求)
import requests

sess = requests.Session()
sess.get("https://xueqiu.com/")
sess.get("https://xueqiu.com/statuses/hot/listV2.json?since_id=-1&max_id=156113&size=15", headers=headers)

代理

import requests
from lxml import etree

headers ={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'}# 配置代理
proxies ={'http':'102.129.157.20:8080'}
page_text = requests.get("https://www.sogou.com/web?query=ip",headers=headers, proxies=proxies).text

tree = etree.HTML(page_text)
content = tree.xpath('//*[@id="ipsearchresult"]/strong//text()')print(content)

代理池

import random

proxy_pool =[{'http':'102.129.157.20:8080'},{'http':'102.129.157.20:8080'}]
page_text = requests.get("https://www.sogou.com/web?query=ip",headers=headers, proxies=random.choice(proxy_pool)).text

异步爬虫

线程池

import requests
from multiprocessing.dummy import Pool
import time

urls =['http://localhost:5000/hello','http://localhost:5000/hello','http://localhost:5000/hello']defgetRequest(url):
    page_text = requests.get(url).text
    return page_text

start = time.time()
pool=Pool(3)
page_list = pool.map(getRequest, urls)for page_text in page_list:print(len(page_text))print('总耗时:', time.time()- start)

生产者消费者模式

"""
生产者,消费者模式
"""from threading import Thread
from queue import Queue
from urllib import request

from lxml import etree
import requests

classProducer(Thread):
    headers ={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ''Chrome/112.0.0.0 Safari/537.36'}def__init__(self, page_queue, img_queue,*args,**kwargs):super(Producer, self).__init__(*args,**kwargs)
        self.page_queue = page_queue
        self.img_queue = img_queue

    defrun(self)->None:whileTrue:if self.page_queue.empty():break
            url = self.page_queue.get()
            self.parse_page(url)defparse_page(self, url):
        response = requests.get(url, headers=self.headers)
        text = response.text
        html = etree.HTML(text)

        img_list = html.xpath('//*[@id="__layout"]//div[@class="expression-list clearfix"]//img')for img in img_list:
            img_url = img.xpath('./@data-src')[0]
            img_name = img.xpath('./@alt')[0]+'.jpg'print(img_name, img_url)
            self.img_queue.put((img_url, img_name))classConsumer(Thread):def__init__(self, page_queue, img_queue,*args,**kwargs):super(Consumer, self).__init__(*args,**kwargs)
        self.page_queue = page_queue
        self.img_queue = img_queue

    defrun(self)->None:whileTrue:if self.page_queue.empty()and self.img_queue.empty():break
            img_url, img_name = self.img_queue.get()
            request.urlretrieve(img_url,f"imgs/{img_name}")print(img_name +"\t 下载完成")defmain():
    page_queue = Queue(3)# 存储页码链接的队列
    img_queue = Queue(10)# 存储解析出来的图片链接# 想要爬取 前 10页的数据for x inrange(1,4):
        url =f"https://www.doutub.com/img_lists/new/{x}"
        page_queue.put(url)for x inrange(2):
        t = Producer(page_queue, img_queue)
        t.start()for x inrange(2):
        t = Consumer(page_queue, img_queue)
        t.start()if __name__ =='__main__':
    main()

单线程+多任务的异步协程

  • 特殊的函数 - 如果一个函数的定义被async关键字修饰,则该函数就是一个特殊的函数。- 特殊函数调用后,返回了一个协程对象- 函数内部的程序语句没有被立即执行
  • 协程 - 特殊函数调用后返回的即是协程对象
  • 任务对象 - asyncio.ensure_future(c)
  • 事件循环:eventLoop- asyncio.get_event_loop() 返回事件循环对象- 需要将任务对象注册到事件循环对象中,且启动事件循环即可
  • wait()方法 - 进行任务对象的挂起操作。- 可以给每一个任务对象赋予一个可被挂起的权限- 挂起:如果挂起一个任务对象就表示让当前正在被执行的任务对象交出cpu的使用权。
  • await关键字:可以保证每一个任务对象的阻塞操作可以被异步执行
  • 核心点:如果特殊函数内部的实现语句中出现了不支持异步模块对应的代码,则会立即中断整个异步效果。
import asyncio
import time

asyncdefgetRequest(url):print("start: ", url)
    time.sleep(2)print("end. ")return'aaa'# 回调函数必须要有一个参数,就是回调函数的调用者(任务对象)defcallback(res,*args,**kwargs):# 特殊函数的返回值可以使用 result函数接受print("result: ", res.result())# 协程对象
c = getRequest("www.baidu.com")# 任务对象
task = asyncio.ensure_future(c)# 任务对象的高级之处: 可以给任务对象绑定回调函数
task.add_done_callback(callback)# 事件循环对象
loop = asyncio.get_event_loop()# 将任务对象放到事件循环对象中,并启动事件循环
loop.run_until_complete(task)

开启多任务异步协程

import asyncio
import time

asyncdefgetRequest(url):print("start: ", url)# time.sleep(2) # 不支持异步模块的代码await asyncio.sleep(2)print("end. ")return'aaa'# 回调函数必须要有一个参数,就是回调函数的调用者(任务对象)defcallback(res,*args,**kwargs):# 特殊函数的返回值可以使用 result函数接受print("result: ", res.result())

start = time.time()
urls =['www.baidu.com','www.jd.com','www.mi.com']
tasks =[]for url in urls:# 协程对象
    c = getRequest("www.baidu.com")# 任务对象
    task = asyncio.ensure_future(c)# 任务对象的高级之处: 可以给任务对象绑定回调函数
    task.add_done_callback(callback)
    tasks.append(task)# 事件循环对象
loop = asyncio.get_event_loop()# 将任务对象放到事件循环对象中,并启动事件循环
loop.run_until_complete(asyncio.wait(tasks))print("花费时间: ", time.time()- start)# 2.0086746215820312

aiohttp

支持异步请求操作的模块

pip install aiohttp

requests 模块不支持异步,需要用

aiohttp

模块代替。异步协程爬虫代码案例:

import asyncio
import time

import aiohttp

asyncdefgetRequest(url):# page_text = await requests.get(url).text   # requests 不支持异步# 基于aiohttp 进行网络请求asyncwith aiohttp.ClientSession()as sess:# 创建一个请求对象"""
        发起请求的操作:
        sess.get/post(url, headers, data/params, proxy='http://ip:port')
        """asyncwithawait sess.get(url)as response:
            page_text =await response.text()# read() => content    text() => textreturn page_text

# 回调函数必须要有一个参数,就是回调函数的调用者(任务对象)defcallback(res,*args,**kwargs):# 此处进行解析
    html_str = res.result()print("result: ",len(html_str))

start = time.time()
urls =['https://www.baidu.com','https://www.jd.com','https://www.mi.com']
tasks =[]for url in urls:# 协程对象
    c = getRequest(url)# 任务对象
    task = asyncio.ensure_future(c)# 任务对象的高级之处: 可以给任务对象绑定回调函数
    task.add_done_callback(callback)
    tasks.append(task)# 事件循环对象
loop = asyncio.get_event_loop()# 将任务对象放到事件循环对象中,并启动事件循环
loop.run_until_complete(asyncio.wait(tasks))print("花费时间: ", time.time()- start)

Selenium

selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题 。
selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器。

官网: https://selenium-python.readthedocs.io/
中文文档:https://selenium-python-zh.readthedocs.io/en/latest/

环境安装

基本操作

from selenium import webdriver

from time import sleep

# 1. 创建一个浏览器对象
bro = webdriver.Chrome(executable_path='./chromedriver.exe')# 2. 发起请求
bro.get("https://www.baidu.com/")# 3. 标签定位
search_ele = bro.find_element_by_id("kw")# 4. 节点交互
search_ele.send_keys("Mac Pro")
sleep(2)
btn_ele = bro.find_element_by_xpath('//*[@id="su"]')
btn_ele.click()
sleep(2)# js 注入
bro.execute_script('window.scrollTo(0, document.body.scrollHeight)')
sleep(5)

bro.close()

相关方法

"""
## 1. 获取页面内容
bro.page_source

## 2. 选择器(find系列)
# ===============所有方法===================
# 1、find_element_by_id   # 通过id查找控件
# 2、find_element_by_link_text  # 通过a标签内容找
# 3、find_element_by_partial_link_text  # 通过a标签内容找,模糊匹配
# 4、find_element_by_tag_name   # 标签名
# 5、find_element_by_class_name  # 类名
# 6、find_element_by_name      # name属性
# 7、find_element_by_css_selector  # 通过css选择器
# 8、find_element_by_xpath       # 通过xpaht选择器

## 3. 获取元素属性
# 重点
# tag.get_attribute('href')  # 找当前控件 的href属性对的值
# tag.text   # 获取文本内容

## 4. 元素交互
# tag.send_keys()  # 往里面写内容
# tag.click()      # 点击控件
# tag.clear()      # 清空控件内容
"""

动作链

动作链这个工具类中封装好了一些基于浏览器自动化的一系列连续的行为动作(如:滑动,拖拽)

from selenium import webdriver
from time import sleep

bro = webdriver.Chrome(executable_path="./chromedriver.exe")
url ='https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'

bro.get(url)# 这里定位的标签出现在了iframe标签之中,会定位失败, # 需要使用 switch_to(frame的ID) 来切换到该frame
bro.switch_to.frame("iframeResult")
div_tag = bro.find_element_by_xpath('//*[@id="draggable"]')# 实例化动作链对象,且让该对象和bro对象进行绑定
action = webdriver.ActionChains(bro)
action.click_and_hold(div_tag)# 点击且长按for i inrange(5):
    action.move_by_offset(20,30).perform()# perform 表示动作链立即执行
    sleep(1)

sleep(2)
bro.close()

无可视化界面的浏览器操作

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time

# 创建一个参数对象,用来控制chrome以无界面模式打开
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')# 创建浏览器对象
browser = webdriver.Chrome(executable_path='./chromedriver.exe', chrome_options=chrome_options)
browser.get('https://www.baidu.com/')
time.sleep(3)# 进行截图
browser.save_screenshot('baidu.png')
browser.close()
标签: python 爬虫 selenium

本文转载自: https://blog.csdn.net/monoplasty/article/details/130554587
版权归原作者 monoplasty 所有, 如有侵权,请联系我们删除。

“【python爬虫一】爬虫基础操作”的评论:

还没有评论