Python爬虫底子总结条记
条记主体内容来自尚硅谷Python爬虫小白教程,老师课讲得很好,非常保举!!!1. 爬虫简介
将整个互联网看作是蜘蛛网,各网站数据为猎物,程序员为狩猎者,因此爬虫顾名思义即程序员通过各种本领获取互联网上的数据。
2. urllib
urllib 是 python 标准库种用于发送网络请求的库,掌握根本命令可以便于批量获取网络数据
2.1 访问服务器
import urllib.request
url = 'http://www.baidu.com'
# 模拟浏览器访问(返回的是HTTPResponse对象)
response = urllib.request.urlopen(url)
# 获取网页内容,读取到的是二进制数据,通过decode解码为utf-8形式
# response还有readlines,getcode,geturl,getheaders等方法
html = response.read().decode('utf-8')
2.2 下载资源
传入资源地址, 下载图片,视频等资源
import urllib.request
# 图片地址
url_retrieve = 'https://img1.baidu.com/it/u=959337756,4186275445&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=889'
# 下载图片并存储到本地,重命名为1.jpg
urllib.request.urlretrieve(url_retrieve, '1.jpg')
2.3 自界说请求对象
为什么必要?
https 请求头部中有 User Agent 字段,使得服务器可以或许识别客户利用的操作体系及版本,CPU 类型、欣赏器及版本等信息,而当利用脚本发出普通请求时,这一字段为空,此时服务端返回的相应内容会有所保留。利用自界说请求对象添加此部门信息即可解决问题。
User Agent 字段获取方式如下
https://i-blog.csdnimg.cn/img_convert/3f08048c38dd02f4f2e7dde323b06c5d.png import urllib.request
url = 'https://www.baidu.com'
header = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36'}
# 自定义请求对象,post请求数据由data关键字传入字典
request = urllib.request.Request(url, headers=header)
# 发送请求
response = urllib.request.urlopen(request)
# 读取响应内容
content = response.read().decode('utf-8')
2.4 请求编码
在 request 中传入中文无法被识别,因此必要将文本转换为 Unicode 格式再传入
import urllib.parse
# 得到周杰伦的unicode编码
name = urllib.qarse.quote('周杰伦')
# 转换多个参数且用&连接【可直接与get请求拼接】
data = {
'wd':'周杰伦',
'sex':'男'
}
# wd=xxxx&sex=yyyy
# 如果用于post请求则还需要使用encode('utf-8')转为字节流
a = urllib.parse.urllencode(data)
2.5 代理服务器
当一个IP地址短时间内多次向服务器发送请求时,大概会被拉黑,此时可以利用代理服务器模仿多用户,实现反爬
import urllib.request
url = 'http://www.baidu.com/s?wd=IP'
header = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36'
}
# 云平台查询得到的IP地址【百度搜索“快代理”】
proxies = {
'http': '8.130.71.75:3128'
}
request = urllib.request.Request(url, headers=header)
# handler可以自定义更复杂的头部信息,此处添加访问IP地址
handler = urllib.request.ProxyHandler(proxies=proxies)
# handler固定使用步骤:handler,builder_opner,open
opener = urllib.request.build_opener(handler)
# 发送请求
response = opener.open(request)
# 读取响应内容
content = response.read().decode('utf-8')
with open('main.html', 'w', encoding='utf-8') as f:
f.write(content)
若手上有大量IP地址,可以通过代理池的方式随机选择访问IP,防止地址被封
proxies_pool = [{'http': '8.130.71.75:1111'},{'http': '8.130.71.75:2222'}]
proxies = random.choice(proxies_pool)
3. 解析网页
3.1 XPath
Python 利用 XPath 提取网页目标元素依赖于 lxml 库
from lxml import etree
# 解析本地的html文件
html_tree = etree.parse('xx.html')
# 解析服务器响应的response
html_tree = etree.HTML(response.read().decode('utf-8'))
# xpath路径解析后结果,返回一个列表
res = html_tree.xpath('xpath路径')
3.2 JSonPath
Python利用 jsonpath 第三方库提取 json 格式相应数据,jsonpath只能解析本地文件
import json
import jsonpath
# 加载json数据
obj = json.load('xxx')
# 具体语法使用时查询即可
res = jsonpath.jsonpath(obj,'jsonpath语法')
3.3 BeautifulSoup
bs4 库作用与 lxml 库雷同,但是效率低,优点是接口设计更符合利用风俗
from bs4 import BeautifulSoup
# 服务器响应的文件生成对象
soup = BeautifulSoup(response.read().decode(),'lxml')
# 本地文件生成对象
soup = BeautifulSoup(open('xx.html'),'lxml')
常用方法
# 找到第一个<a>
soup.a
# 返回第一个<a>标签的所有属性,以字典的形式存储
soup.a.attrs
# 返回当前定位元素中value属性值
soup.attrs.value
# 找到第一个title为xxx且classw为yyy的<a>
soup.find('a',title='xxx',class_='yyy')
# 找到所有<a>和<span>标签,只返回前两个
soup.find_all(['a','span'],limit=2)
# 返回所有<a>,逗号分隔拼接可以获取多个不同标签
soup.select('a')
# 支持类选择器【.】,Id选择器【#】以及属性选择器
# 支持层级选择器【空格是不严格子代,>是严格子代】
# 查找拥有id的属性的<li>标签,也可以指定id为具体值【用双引号】
soup.select('li')
# 获取节点文本内容
obj.get_text()
# 通过key,value的格式可以获得对应属性值
obj['name']
4. UI自动化
有些网页当利用请求的方式无法获得全部数据,因此必要利用UI自动化的方式获取目标数据
Selenium 提供了 UI 自动化方案,但是加载页面效率较低,可以考虑利用无欣赏器界面的自动化
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
# 获得浏览器对象
def share_brower(browser_path='D:\Chrome\Google\Chrome\Application\chrome.exe'):
# 驱动路径
option = Options()
# 设置浏览器启动地址
option.binary_location = browser_path
option.add_argument('--headless')# 无头模式
option.add_argument('--disable-gpu')# 禁用gpu加速
# 创建浏览器对象
browser = webdriver.Chrome(options=option)
return browser
# 上网
url = 'http://www.baidu.com/'
browser = share_brower()
browser.get(url)
# 截图
browser.save_screenshot('baidu.png')
5. requests库
requests 是一个用于发送请求的第三方库,相对于 urllib 而言操作更加便捷
# request 发送请求后得到的返回值记为 r
# 得到返回文本
r.text
# 定制编码方式
r.encoding
# 获取请求的ur1
r.url
# 返回文本的字节类型
r.content
# 响应的状态码
r.status_code
# 响应的头信息
r.headers
发送请求样例
若要保证多个请求在同一个域里,可以通过获取 session 对象再举行请求调用
import requests
url = 'https://www.baidu.com/s'
# 请求头
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36'
}
# 请求参数
data = {
'wd': '广东'
}
# 传入,post请求中params对应是data关键字
r = requests.get(url, params=data, headers=headers)
# 指定编码
r.encoding = 'utf-8'
print(r.text)
开启代理
# 只需要准备好ip和端口,传入proxies参数即可
proxy = {
'http':'xxx.xxx.xxx.xxx:yyy'
}
request.get(url,params,headers,proxies=proxy)
6. scrapy库
Scrapy 是一个为了爬取网站数据,提取结构性数据而编写的应用框架。可以应用在包罗数据挖掘、信息处置惩罚或存储历史数据等一系列的程序中
6.1 底子结构介绍
# 创建爬虫项目,名称为scrapy_test_project
scrapy startproject scrapy_test_project
https://i-blog.csdnimg.cn/img_convert/a793f7cf08b6391d0a0a6d611930c660.png 项目组成介绍
项目名称
项目名称
spiders
__init__.py
自定义爬虫文件 # 实现爬虫核心功能的文件
__init__.py
items.py # 定义数据结构的地方,是一个继承自scrapy.Item的类
middlewares.py # 中间件,代理
pipelines.py # 管道文件,里面只有一个类,用于处理下载数据的后续处理,默认是300 优先级,值越小优先级越高(1-1000)
settings.py # 配置文件,比如是否遵守robots协议等
进入到 spiders 目次下,天生爬虫文件
# 创建一个叫baidu的爬虫,用于爬取www.baidu.com内容
scrapy genspider baidu www.baidu.com
# 执行爬虫【在根目录下的settings中注释ROBOTSTXT_OBEY = True】
scrapy crawl baidu
https://i-blog.csdnimg.cn/img_convert/1c1daaf4058ef61d2338f5349eb41395.png response的属性和方法
# 获取响应的字符串
response.text
# 获取的是二进制数据
response.body
# xpath过滤
response.xpath()
# 提取selector对象的data属性值
response.extract()
# 提取selector列表的第一个数据
response.extract_first()
实行过程简介
https://i-blog.csdnimg.cn/img_convert/b3646804b9a88f89d06f4847f5953ae2.png # 开启调试模式,可在控制台查看response相关信息
scrapy shell 目标网站
https://i-blog.csdnimg.cn/img_convert/dd10e81bc54012f7087beffef69ca728.png settings.py 日记设置
# 设置日志显示等级(CRITICAL,ERROR,WARNING,INFO,DEBUG)
# 默认等级是DEBUG,只要出现了DEBUG或以上等级的日志都会被打印
LOG_LEVEL = DEBUG
# 将屏幕显示的信息全部记录到文件中,屏幕不再显示,文件以.log结尾
LOG_FILE = xxx.log
6.2 爬取当当网数据实战
我们的目标是获取青春爱情文学前三页的全部书名,图片与代价信息
https://i-blog.csdnimg.cn/img_convert/87aca2d6aaf68759c938a3e6e5fcce55.png
[*] 创建爬虫项目,手动创建 books 以及 books/img 目次方便后续存储相干信息
# 创建名为scrapy_dangdang的爬虫项目
scrapy startproject scrapy_dangdang
https://i-blog.csdnimg.cn/img_convert/4a8d27d3d133ac8c0e94f55b1a674263.png
[*] 编辑数据结构文件 items.py ,将必要存储的变量都交由框架管理
import scrapy
class ScrapyDangdangItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 要下载的数据都有什么
# 图片
src = scrapy.Field()
# 名字
name = scrapy.Field()
# 价格
price = scrapy.Field()
[*] 在 spiders 目次下创建爬虫核心文件,指明初始页面并命名为 dangdang
scrapy genspider dangdang https://category.dangdang.com/pg1-cp01.01.02.00.00.00.html
根据处置惩罚逻辑编辑该文件
import scrapy
from scrapy_dangdang.items import ScrapyDangdangItem
class DangdangSpider(scrapy.Spider):
# 爬虫名称
name = "dangdang"
allowed_domains = ["category.dangdang.com"]
start_urls = ["https://category.dangdang.com/pg1-cp01.01.02.00.00.00.html"]
# 需要爬取的文章页码
page = 1
# 执行爬虫文件时自动调用此方法
def parse(self, response):
# 根据调试网页获得的目标xpath路径
# src = '//ul[@class='bigimg']//li/a/img/@data-original'
# alt = '//ul[@class="bigimg"]//li/a/img/@alt'
# price = '//ul[@class='bigimg']//li/p[@class='price']/span/text()'
li_list = response.xpath('//ul[@class="bigimg"]//li')
for li in li_list:
# 懒加载图片,data-original属性值是真实地址
src = li.xpath('.//a/img/@data-original').extract_first()
# data-original不存在时,使用src数属性值作为地址
if src is None:
src = li.xpath('.//a/img/@src').extract_first()
name = li.xpath('.//a/img/@alt').extract_first()
price = li.xpath(
'.//p[@class="price"]/span/text()').extract_first()
# 将解析的目标值封装并交由管道处理
book = ScrapyDangdangItem(src=src, name=name, price=price)
yield book
# 爬取前3页的数据
if self.page <= 2:
self.page += 1
# 新页面地址
url = f'http://category.dangdang.com/pg{self.page}-cp01.01.02.00.00.00.html'
# scrapy.Request是scrapy的get请求,callback传入需要调用的下一个函数
# 此处是向url发送get请求后重新调用parse方法
yield scrapy.Request(url, callback=self.parse)
[*] 编辑管道文件 pipelines.py,用于下载处置惩罚爬虫所返回的数据
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
import urllib.request
# 用于存储json文件
class ScrapyDangdangPipeline:
# 在爬虫文件开始前执行的方法
def open_spider(self, spider):
self.res = []
def process_item(self, item, spider):
# 将单引号替换为双引号
temp = str(item).replace('\'', '\"')
self.res.append(temp)
return item
# 在爬虫文件结束后执行的方法
def close_spider(self, spider):
with open('./books/books.json', 'w', encoding='utf-8') as f:
# 以逗号作为分隔符将元素拼接并写入json文件
f.write(f'[{",".join(self.res)}]')
# 用于处理图片文件
class DangDangDownloadPipeline:
# 在爬虫文件开始前执行的方法
def open_spider(self, spider):
pass
def process_item(self, item, spider):
pic_url = 'http:' + item.get('src')
pic_name = './books/img/' + item.get('name') + '.jpg'
urllib.request.urlretrieve(pic_url, pic_name)
return item
# 在爬虫文件结束后执行的方法
def close_spider(self, spider):
pass
管道处置惩罚设计完毕后,还必要共同 settings.py 设置管道除了优先级,同时记得解释ROBOTSTXT_OBEY = True【君子协议,为 True 则不允许爬取特定网站】
ITEM_PIPELINES = {
# 值越小,管道优先级越高
"scrapy_dangdang.pipelines.ScrapyDangdangPipeline": 300,
"scrapy_dangdang.pipelines.DangDangDownloadPipeline": 301,
}
[*] 进入 spiders 目次,实行爬虫文件,完成资源爬取
scrapy crawl dangdang
https://i-blog.csdnimg.cn/img_convert/bae58c8bafc2ead2fdca17b40a056c56.png https://i-blog.csdnimg.cn/img_convert/03e99cd6dea93808942f0e21ca91aa9a.png
6.3 post请求处置惩罚
先前利用 start_urls 的方式指定初始访问界面,但在post请求中由于必要请求头,因此无法利用这种方式,以是针对post请求我们必要重新界说一种方式举行处置惩罚
import scrapy
import json
class TransPostSpider(scrapy.Spider):
name = "trans_post"
allowed_domains = ["fanyi.baidu.com"]
# post请求需要指定请求体,start_urls无法做到
# start_urls = ["https://fanyi.baidu.com/mtpe-individual/multimodal#/"]
# 自定义请求体发送post请求
def start_requests(self):
url = 'https://fanyi.baidu.com/sug'
data = {
'kw': '你好'
}
# scrapy中的post,callback指定请求完毕后后续处理的函数
yield scrapy.FormRequest(url, formdata=data, callback=self.parse)
def parse(self, response):
content = json.loads(response.text)
print(content)
7. CrawlSpider
CrawlSpider 继承至 scrapy.Spider,在解析网页内容的时候,它可以根据链接规则提取出指定的链接,然后再向这些链接发送请求,非常实用于爬取网页后必要提取链接举行二次爬取的环境。
其爬虫类创建命令稍有差别
# 创建爬虫项目
scrapy startproject scrapy_dushu
# 爬虫类名称为read,爬取网站为www.dushu.com
scrapy genspider -t crawl read https://www.dushu.com/book/1107_1.html
利用链接提取器过滤得到目标链接
scrapy.linkextractors.LinkExtractor(
allow=(), # 通过正则表达式过滤
restrict_xpaths=(), # 通过xpath过滤(定位到a元素即可)
)
爬取读书网实战
我们的目标是获取计算机网络/读书网首页所能看见页面里全部书名,图片链接信息
https://i-blog.csdnimg.cn/img_convert/7c5a2518cddbe6f564cf02ecc44d185a.png 除了爬虫核心函数有所差别,其余setting,pipeline,items的用法雷同,此处不再赘述,根据需求自行修改即可
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_dushu.items import ScrapyDushuItem
class ReadSpider(CrawlSpider):
name = "read"
allowed_domains = ["www.dushu.com"]
start_urls = ["https://www.dushu.com/book/1107_1.html"]
rules = (Rule(
LinkExtractor(
# 正则表达式写法
# allow=r'/book/1107_\d+\.html',
# xpath写法
restrict_xpaths=("//div[@class='pages']/a")
),
# 重复调用的函数名称
callback="parse_item",
# 为False时不会在新页面中再次调用匹配规则,即最初过滤得到的链接不会实时变动
follow=False),)
def parse_item(self, response):
# 定位到所有图片
img_list = response.xpath(
"//div[@class='book-info']//a/img")
for img in img_list:
# 获取图书名称
name = img.xpath("./@alt").extract_first()
# 获取图书封面图片地址
src = img.xpath("./@data-original").extract_first()
if src is None:
src = img.xpath("./@src").extract_first()
# 封装为数据结构交由管道处理
book = ScrapyDushuItem(name=name, src=src)
yield book
https://i-blog.csdnimg.cn/img_convert/17d741dff53d052b13070c84bcdeda53.png
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]