python爬虫笔记

news/2025/2/12 18:50:36/

Python爬虫笔记

一. Urllib

1. 基础请求

  • 指定url
  • 请求
  • 返回值解码
  • 返回结果的一些操作
import urllib.request as req
# 定义一个url
url = 'http://www.baidu.com'# 发送请求获得相应
res = req.urlopen(url)# read返回字节形式的二进制数据,需要用指定编码来解码
content = res.read().decode('utf-8')# 读5个字节
content2 = res.read(5)# 读一行
content3 = res.readline()# 一行一行全部读完,返回一个数组
content4 = res.readlines()# 获取状态码,如果是200就是正常的
code = res.getcode# 获取头信息
res.getheaders()# 获取请求的url
res.geturl()

下载

url = 'http://www.baidu.com'
req.urlretrieve(url, 'baidu.html')

UA校验和Request对象

  • 在headers中携带了浏览器和操作系统等信息,叫user-agent,是网站的一种反爬机制,需要在header中携带
  • ua只需要在浏览器中的network中随便找一个请求就可以找到ua信息
  • 之后请求的时候,不是在req.urlopen中直接传入url了,而是传入一个Request对象
import urllib.request as ureq
# 下载网页/视频/照片
url = 'https://www.baidu.com'# UA全称UserAgent 是个请求头信息,让浏览器能识别用户的操作系统版本,cpu类型等等信息
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.46'
}
# 构造请求对象
request = ureq.Request(url=url, headers=headers)
# 发送请求的时候放进去的是一个request对象
res = ureq.urlopen(request)
content = res.urlopen(res)

get请求

  • get请求的参数是在url中的,但是请求的时候有中文的时候,需要编码成gbk才行
  • 使用urllib.parse.quote来将中文编码
# 请求url中的中文要被转换为Unicode编码,才能正常进行访问
import urllib.parse
import urllib.request as ureq
name = urllib.parse.quote('周杰伦')
# 下载网页/视频/照片
url = 'https://www.baidu.com/s?wd='+name# UA全称UserAgent 是个请求头信息,让浏览器能识别用户的操作系统版本,cpu类型等等信息
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.46'
}
# 构造请求对象
request = ureq.Request(url=url, headers=headers)
# 发送请求的时候放进去的是一个request对象
res = ureq.urlopen(request)
print(res.read())

post请求

  • post请求和get的最大不同就是post请求的请求参数是放在请求体里的,不在url中直接写出来
  • 注意!!!:先用urlencode编码之后,还要编码一次成utf-8,请求参数应该写在一个字典中
import urllib.parse
import urllib.request as ureq
import json
parms = {'text': 'red',
}
# post请求的参数必须要编码,注意要调用encode方法
data = urllib.parse.urlencode(parms).encode('utf-8')
url = 'https://dict.youdao.com/keyword/key'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.46','Cookie': 'OUTFOX_SEARCH_USER_ID=-1182920945@10.110.96.160; OUTFOX_SEARCH_USER_ID_NCOO=977276189.4843129'#     如果请求不成功可能是头信息不足,比如缺了cookie
}
request = urllib.request.Request(url=url, data=data, headers=headers)
res = ureq.urlopen(request)
# 返回JSON对象,转换为一个字典类型
content = res.read().decode('utf-8')
content = json.loads(content)
print(content)

cookies

  • 一般登录信息都存放在cookies中,需要登录才能访问的界面如果是用的cookie校验的化,在header中携带cookie才可以进行访问

headler

import urllib.request
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.46'
}
url = 'https://movie.douban.com/j/chart/top_list?type=25&interval_id=100%3A90&action=&start=0&limit=20'
request = urllib.request.Request(url=url, headers=headers)
# 获取handler对象
handler = urllib.request.HTTPHandler()
# 获取opener对象
opener = urllib.request.build_opener(handler)
# 调用open方法
res = opener.open(request)print(res.read().decode('utf-8'))

handler方式

  • 用自己的ip可能不安全或者访问过于频繁被封ip,可以使用代理ip
  • 用handler和opener方式请求可以使用代理ip
import urllib.request
import random
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.46'
}
url = 'https://www.baidu.com/s?wd=ip'
request = urllib.request.Request(url=url, headers=headers)
# 用random随机在代理池中选择
proxy_pool = [{'http': '61.216.156.222:60805'},{'http': '61.216.156.222:60808'},{'http': '61.216.156.222:60802'},
]
proxy = random.choice(proxy_pool)
# 获取handler对象
handler = urllib.request.ProxyHandler()
# 获取opener对象
opener = urllib.request.build_opener(handler)
# 调用open方法
res = opener.open(request)
content = res.read().decode('utf-8')
with open('代理.html', 'w', encoding='utf-8') as f:f.write(content)

xpath

下载和安装

按这篇文章
解压之后在chrome中开发者模式中选择解压好之后的文件夹即可完成安装

  • 重启浏览器,ctrl+shift+x 出现小黑框

基础解析语法

from lxml import html
import urllib.request
import json
et = html.etree# 创建树节点
html_tree = et.parse('demo01.html')# xpath路径
# //表示所有子孙节点
# /表示子节点
res1 = html_tree.xpath('//body/ul/li')# [@id]可以获取当前层级下所有写了id的标签
res2 = html_tree.xpath('//body/ul/li[@id]')
# 也可以指定id是谁来获取
res3 = html_tree.xpath('//body/ul/li[@id=2]')
# /text可以获取标签里的文本信息
res4 = html_tree.xpath('//body/ul/li[@id=2]/text()')
# @class可以获取该元素的class属性
res5 = html_tree.xpath('//body/ul/li[@id=2]/@class')
# 模糊查询
res6 = html_tree.xpath('//body/ul/li[contains(@id, "l")]')
# 模糊查询2
res7 = html_tree.xpath('//body/ul/li[starts-with(@id, "l")]')
# 逻辑运算
res8 = html_tree.xpath('//ul/li[@id=1 or @class="adfass"]')

beautifulSoup

可以像操作对象一样进行标签的选择

基础操作

from bs4 import BeautifulSoup
# 打开本地页面数据,注意默认编码格式是gbk
bs = BeautifulSoup(open('demo01.html', encoding='utf-8'), 'lxml')
# 根据标签查找第一个符合要求的
res1 = bs.ul.li
# 输出标签的属性
res2 = bs.ul.li.attrs

两种find函数

# find函数,可以根据一些条件找到符合条件的第一个
res3 = bs.find('li', id=1)
res4 = bs.find('li', class_="adfass")# find_all 找到所有的,寻找多个的时候要放到一个列表中
res5 = bs.findAll(['li', 'body', 'ul'])
# 用limit可以控制返回前几个
res6 = bs.findAll(['li', 'body', 'ul'], limit=2)

select选择器


# 使用select,可以使用一些选择器语法
res7 = bs.select('li')
# 类选择器,加一个.
res8 = bs.select('.adfass')
# id选择器,加一个#
res9 = bs.select('#l1')
# 属性选择器,选择li中有id的
res10 = bs.select('li[id]')
res10 = bs.select('li[id="l1"]')# 层级选择器
# 后代选择器,用空格分开,两者之间只要是后代关系,隔多少层级都可以
res11 = bs.select('div li')# 子代选择器,用>隔开,只有第一代子代会被选中
res12 = bs.select('div > ul')# 获取多个标签
res13 = bs.select("li, a, div")# 获取节点信息
obj = res13[5]
s1 = obj.get_text()
attr = obj.attrs
print(attr)

selenium

驱动浏览器去上网,骗过反爬机制

使用方式

  1. 先去下载对应浏览器对应版本的驱动程序
  2. 将驱动程序放在当前目录下
  3. pip install selenium

基础操作

from selenium import webdriver
import time
path = 'chromedriver.exe'
browser = webdriver.Chrome(path)
# 控制浏览器访问这个url
browser.get('https://www.baidu.com/')
# 获取网页源码
content = browser.page_source
# 获取元素
# 通过xpath表达式获取
time.sleep(2)
input = browser.find_element(by='xpath', value='//input[@id="kw"]')
input.send_keys('周杰伦')btn = browser.find_element(by='xpath', value='//input[@id="su"]')
btn.click()# 通过js代码来操控
time.sleep(4)js = "window.scrollTo(0, document.body.scrollHeight)"
browser.execute_script(js)

交互操作

from selenium import webdriver
path = 'chromedriver.exe'
browser = webdriver.Chrome(path)
# 控制浏览器访问这个url
browser.get('https://cn.bing.com/')
# 获取网页源码
content = browser.page_source
# 获取元素
# 通过xpath表达式获取
btn = browser.find_element(by='xpath', value='//label[@id]')print(tag)

requests库

requests是python原生的可用于爬虫的库,比urllib方便,比如get和post的时候不用对参数进行编码,或者创建Request对象再进行请求‘

基础操作

url = 'https://www.baidu.com/s?'
headers = {'User-Agent': 'xxxxxx',
}
data ={'wd': '周杰伦'
}
# params:请求参数,无需像urllib一样编码了
res = requests.get(url, params=data, headers=headers)
res.encoding = 'utf-8'
text = res.text  # 字符串形式的页面源码
res_url = res.url
content = res.content  # 返回二进制数据
code = res.status_code  # 状态码
headers = res.headers  # 头信息

post请求

注意点:

  1. 留意那些隐藏了登录参数,可以进行错误登录查看请求内容,然后去源码中进行定位获取
  2. 验证码的url每次访问都是出现不一样的,因此需要用到session
  3. 可以使用超级鹰等验证码识别平台进行验证码的识别
url = 'https://fanyi.baidu.com/sug'
headers = {'User-Agent': 'xxxx',
}
data = {'kw': 'eye'
}
proxy = {'http': 'xxx.xxx.xxx:xxxx'
}
res = requests.post(url=url, data=data, headers=headers, proxies=proxy)
res.encoding='utf-8'
res = json.loads(res.text, encoding='utf-8')
print(res)

验证码登录案例

import requests
import bs4
import urllib.request
login_index_url = 'https://so.gushiwen.cn/user/login.aspx?from=http://so.gushiwen.cn/user/collect.aspx'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.46',
}
# 有两个隐藏起来的用于验证的,需要先获取
res = requests.get(url=login_index_url, headers=headers)
soup = bs4.BeautifulSoup(res.text, features='lxml')
VIEWSTATE = soup.select('#__VIEWSTATE')[0].attrs['value']
VIEWSTATEGENERATOR = soup.select('#__VIEWSTATEGENERATOR')[0].attrs['value']
code_url = soup.select('#imgCode')[0].attrs['src']
code_url = 'https://so.gushiwen.cn/'+code_url# 如果使用的下载的话,等下将账号密码验证码发过去的时候,那个验证码请求回来的东西就和之前不一样了
# urllib.request.urlretrieve(code_url, filename='code.jpg')
# 要使用session
session = requests.session()
response_code = session.get(login_index_url)
# 图片是二进制数据下载下来的
content_code = response_code.content
with open('code.jpg', 'wb')as fp:fp.write(content_code)print(code_url)
code = input('请输入验证码')
login_url = 'https://so.gushiwen.cn/user/login.aspx?from=http%3a%2f%2fso.gushiwen.cn%2fuser%2fcollect.aspx'
data = {'__VIEWSTATE': VIEWSTATE,'__VIEWSTATEGENERATOR': VIEWSTATEGENERATOR,'from': 'http://so.gushiwen.cn/user/collect.aspx','email': '18851605189','pwd': 'Xboxoneps4psv','code': code,'denglu': '登录'
}
# 这里的请求也要用session对象的请求
res = session.post(url=login_url, data=data, headers=headers)
print(res.text)

Scrapy

常用的爬虫框架

使用

  1. pip install scrapy
  2. 初始化scrapy项目
scrapy startproject项目名称
  1. spiders文件夹中创建爬虫文件
scrapy genspider 文件名 起始域名
  1. 将settings中的robot协议改为否
  2. 执行爬虫程序
scrapy crawl 爬虫名称

项目结构

创建了scrapy工程之后默认会创建几个文件

  • spiders:用来存放爬虫文件的
  • items:自定义数据机构读的地方
  • middleware:中间件
  • pipelines:管道,用来处理下载数据的
  • settings:配值文件

scrapy工作原理

工作原理

使用管道下载数据

  1. 在setting中开启管道
    在这里插入图片描述
  2. 在items中将要储存的数据都有什么用**scrapy.Field()**创建Field对象
# 比如这里我要存的有三个字段
class DangdangItem(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()#  在这里定义数据都有什么src = scrapy.Field()name = scrapy.Field()price = scrapy.Field()
  1. 在爬虫主程序中,导入items中的类,并且将爬到的数据作为构造函数的参数,实例化有数据的对象,yield返回每次读到的数据,pipeline会读取到
    在这里插入图片描述
  2. pipeline中接收:process_item中的item参数就是yield返回的一个个值,这里可以定义生命周期函数,在开始爬虫前打开一个文件,爬虫结束后关闭,减少io操作
class DangdangPipeline:def open_spider(self, spider):self.fp = open('dangdang.json', 'w', encoding='utf-8')# item就是yield出来的book对象def process_item(self, item, spider):self.fp.write(str(item))return itemdef close_spider(self, spider):self.fp.close()

多管道下载

  1. 再创建一个类,也有一个process_item方法
  2. settings中的管道那里,将新增类对应的名字加入字典中,添加一条管道
import urllib.requestclass DangdangPipeline:def open_spider(self, spider):self.fp = open('dangdang.json', 'w', encoding='utf-8')# item就是yield出来的book对象def process_item(self, item, spider):self.fp.write(str(item))return itemdef close_spider(self, spider):self.fp.close()# 开启另一个管道下载图片
class DownloadPics:def process_item(self, item, spider):url = item.get('src')url = 'http:'+urlfilename = './book/'+item.get('name')+'.jpg'urllib.request.urlretrieve(url=url, filename=filename)return item

在这里插入图片描述

多页面下载

  • scrapy.Request可以发起get请求,在parse方法内部,用yield调用可以每次循环都调用
import scrapy
from dangdang.items import DangdangItemclass Dangdang01Spider(scrapy.Spider):name = 'dangdang01'allowed_domains = ['category.dangdang.com']start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']current_page = 1def parse(self, response):li_list = response.xpath('//ul[@id="component_59"]/li')# xpath的结果可以继续进行xpath# 要加.表示相对于当前的xpath的路径for li in li_list:src = li.xpath('.//img/@data-original').extract_first()if src:src = srcelse:src = li.xpath('.//img/@src').extract_first()name = li.xpath('.//img/@alt').extract_first()price = li.xpath('.//p[@class="price"]/span/text()').extract_first()# 导入items中的class,并且用yield交给管道book = DangdangItem(src=src, name=name, price=price)yield bookif self.current_page <= 10:self.current_page += 1url = f'http://search.dangdang.com/?key=%C8%FD%CC%E5&act=input&page_index={self.current_page}'yield scrapy.Request(url=url, callback=self.parse)

进入页面下载

  • 需求:在一个页面获取到一个href链接后,访问这个链接
  • 也是用scrapy.Request(url, callback=要调用的函数名, meta=可以通过这个向要调用的函数中传参)
import scrapy
from DYTT.items import DyttItemclass MovieSpider(scrapy.Spider):name = 'movie'allowed_domains = ['dygod.net']start_urls = ['https://www.dygod.net/html/gndy/china/index.html']def parse(self, response):a_list = response.xpath('//table//a[2]')for a in a_list:title = a.xpath('./@title').extract_first()href = a.xpath('./@href').extract_first()href = 'https://www.dygod.net' + href# 对链接进行访问,可以将值用meta传递給调用的函数yield scrapy.Request(url=href, callback=self.parse_second, meta={'title': title})def parse_second(self, res):src = res.xpath('//div[@id="Zoom"]//img/@src')title = res.meta['title']movie = DyttItem(title=title, src=src)yield movie

日志

  • 日志等级
LOG_LEVEL = 'CRITICAL/ERROR/WARNING/INFO/DEBUG'  # 对应不同的日志等级
  • 输出日志
LOG_FILE = 'log01.log'

post请求

  • post请求需要携带请求体才有意义
  • 直接通过parse方法,带着起始url访问是无效的
  • 要通过start_request方法,指定好请求参数之类的再请求
  • 通过scrapy.FormRequest发送post请求
import scrapy
import jsonclass TestpostSpider(scrapy.Spider):name = 'testPost'allowed_domains = ['fanyi.baidu.com']start_urls = ['https://fanyi.baidu.com/sug/']def start_requests(self):url = 'https://fanyi.baidu.com/sug/'data = {'kw': 'red'}# 发送post创建FormRequestyield scrapy.FormRequest(url=url, formdata=data, callback=self.second_parse)def second_parse(self, res):content = res.textobj = json.loads(content, encoding='utf-8')print(obj)

http://www.ppmy.cn/news/98266.html

相关文章

zabbix配置钉钉告警(附含钉钉告警脚本 · 实战亲测无任何问题)

&#x1f341;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; 文章目录 钉钉上操作&#xff08;钉钉告警以关…

首发Yolov8优化:Adam该换了!斯坦福最新Sophia优化器,比Adam快2倍 | 2023.5月斯坦福最新成果

1.Sophia优化器介绍 斯坦福2023.5月发表的最新研究成果,他们提出了「一种叫Sophia的优化器,相比Adam,它在LLM上能够快2倍,可以大幅降低训练成本」。 论文:https://arxiv.org/pdf/2305.14342.pdf 本文介绍了一种新的模型预训练优化器:Sophia(Second-order Clippe…

sql-labs SQL注入平台——第二关Less-2 GET - Error based - Intiger based (基于错误的GET整型注入)

Less-2 GET - Error based - Intiger based (基于错误的GET整型注入) 一、先确认漏洞是否存在 &#xff08;1&#xff09;查询 id1返回查询结果正常 &#xff08;2&#xff09;查询 id1’返回查询结果报错&#xff0c;可能存在SQL注入 &#xff08;3&#xff09;查询 id1 …

MybatisPlus处理业务数据新思路

文章目录 [toc] 1.问题2.新姿势3.总结 1.问题 由于之前搞了一个停车场的项目&#xff0c;有一个区域的停车场收费被投诉了被举报没有按照政府要求来计费&#xff0c;所以需要将之前的那些停车计费的数据重新计算&#xff0c;将多缴费的钱拿去交罚款&#xff0c;这个就很坑&…

机器学习 | SVD奇异值分解

本文整理自哔哩哔哩视频&#xff1a;什么是奇异值分解SVD–SVD如何分解时空矩阵 &#x1f4da;奇异值分解是什么&#xff1f; M是原始矩阵&#xff0c;它可以是任意的矩阵&#xff0c;奇异值分解就是将它分解为三个矩阵相乘。U和V是方阵&#xff0c;∑是不规则矩阵&#xff0c;…

js获取Element元素的常用方法

js中获取Element元素的常用方法有以下四种&#xff1a; 【方法一】根据元素ID&#xff1a;document.getElementById() 【方法二】根据元素标签&#xff1a;document.getElementsByTagName() 【方法三】根据元素class名&#xff1a;document.getElementsByClassName() 【方法…

RabbitMQ学习-备份交换机

有了 mandatory 参数和回退消息&#xff0c;我们获得了对无法投递消息的感知能力&#xff0c;有机会在生产者的消息 无法被投递时发现并处理。但有时候&#xff0c;我们并不知道该如何处理这些无法路由的消息&#xff0c;最多打个日志&#xff0c;然 后触发报警&#xff0c;再来…

定积分的计算(换元法)习题

前置知识&#xff1a;定积分的计算&#xff08;换元法&#xff09; 习题1 已知 f ( x ) f(x) f(x)&#xff0c;计算 ∫ a b f ′ ( 2 x ) d x \int_a^bf(2x)dx ∫ab​f′(2x)dx 解&#xff1a;原式 1 2 ∫ a b f ′ ( 2 x ) d ( 2 x ) 1 2 f ( 2 x ) ∣ a b 1 2 [ f ( 2 …