条记主体内容来自尚硅谷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 字段获取方式如下
- 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[id]')
- # 获取节点文本内容
- 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
复制代码 项目组成介绍
- 项目名称
- 项目名称
- 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
复制代码 response的属性和方法
- # 获取响应的字符串
- response.text
- # 获取的是二进制数据
- response.body
- # xpath过滤
- response.xpath()
- # 提取selector对象的data属性值
- response.extract()
- # 提取selector列表的第一个数据
- response.extract_first()
复制代码 实行过程简介
- # 开启调试模式,可在控制台查看response相关信息
- scrapy shell 目标网站
复制代码 settings.py 日记设置
- # 设置日志显示等级(CRITICAL,ERROR,WARNING,INFO,DEBUG)
- # 默认等级是DEBUG,只要出现了DEBUG或以上等级的日志都会被打印
- LOG_LEVEL = DEBUG
- # 将屏幕显示的信息全部记录到文件中,屏幕不再显示,文件以.log结尾
- LOG_FILE = xxx.log
复制代码 6.2 爬取当当网数据实战
我们的目标是获取青春爱情文学前三页的全部书名,图片与代价信息

- 创建爬虫项目,手动创建 books 以及 books/img 目次方便后续存储相干信息
- # 创建名为scrapy_dangdang的爬虫项目
- scrapy startproject scrapy_dangdang
复制代码
- 编辑数据结构文件 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[1]/img/@data-original'
- # alt = '//ul[@class="bigimg"]//li/a[1]/img/@alt'
- # price = '//ul[@class='bigimg']//li/p[@class='price']/span[1]/text()'
- li_list = response.xpath('//ul[@class="bigimg"]//li')
- for li in li_list:
- # 懒加载图片,data-original属性值是真实地址
- src = li.xpath('.//a[1]/img/@data-original').extract_first()
- # data-original不存在时,使用src数属性值作为地址
- if src is None:
- src = li.xpath('.//a[1]/img/@src').extract_first()
- name = li.xpath('.//a[1]/img/@alt').extract_first()
- price = li.xpath(
- './/p[@class="price"]/span[1]/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 目次,实行爬虫文件,完成资源爬取
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元素即可)
- )
复制代码 爬取读书网实战
我们的目标是获取计算机网络/读书网首页所能看见页面里全部书名,图片链接信息
除了爬虫核心函数有所差别,其余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
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |