作者主页:编程指南针
作者简介:Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师
主要内容:Java项目、Python项目、前端项目、人工智能与大数据、简历模板、学习资料、面试题库、技术互助
收藏点赞不迷路 关注作者有好处
文末获取源码
Python框架之网络爬虫框架
一,初识网络爬虫
网络爬虫可以按照指定的规则(网络爬虫算法)自动浏览或抓去网络中的信息,通过Python可以很轻松的编写爬虫程序或者是脚本。我们常见的搜索引擎就离不开网络爬虫,百度的搜索引擎的爬虫名字叫作百度蜘蛛,它每天都会在海量的互联网信息中进行爬取,收集并整理互联网上的网页、图片视频等信息,然后当用户在百度搜索引擎中输入对应的关键词时,百度将从收集的网络信息中找出相关的内容,再按照一定的顺序将信息展现给用户。百度蜘蛛在工作的过程当中,搜索引擎会构建一个调度程序,来调度百度蜘蛛的工作,这些调度程序都是需要使用一定的算法来实现。采用不同的算法,爬虫的工作效率会有所不同,爬取的结果也会有所差异,所以在学习爬虫的时候不仅需要了解爬虫的实现过程,还需要了解一些常见的爬虫算法,有时还需自定相应的算法。
爬虫按实现的技术和结构一般分为如下几类:通用网络爬虫、聚焦网络爬虫、增量式网络爬虫、深层网络爬虫。实际开发中,往往采有这几类的组合体。
网络爬虫的基本工作流程如下所示:
(1)获取初始的URL,该URL地址是用户自己制定 的初始爬取的网页。
(2)爬取对应URL地址的网页时,获取新的URL地址。
(3)将新的URL地址放入URL队列中。
(4)从URL队列中读取新的URL,然后依据新的URL爬取网页,同时从新的网页中获取新的URL地址,重复上述爬取过程。
(5)设置停止条件,如果没有设置停止条件时,爬虫会一直爬取下去,直到无法获取新的URL地址为止。设置了停止条件后,爬虫会在满足停止条件时停止爬取。
基本流程图如下所示:
二,网络爬虫常用的技术
2.1 Python的网络请求
本小节主要介绍在Python中实现HTTP网络请求常见的三种方式 :urllib、urllib3以及requests.
1.urllib 模块
urllib是Python自带模块,该模块中提供了一个urlopen()方法,通过该方法指定URL发送网络请求来获取数据,urllib提供了多个子模块,具体的模块名称与含义如下图所示。
示例:
#爬虫示例
import urllib.request #导入模块
#打开指定需要爬取的网页
response = urllib.request.urlopen("http://www.baidu.com")
html = response.read() #读取网页代码
print(html) #打印读取内容
上面是通过get请求来获取的网页内容,下面通过post请求来获取网页内容
#爬虫示例
import urllib.request #导入模块
import urllib.parse
#将数据使用urlencode编码处理后,再使用encoding设置为utf-8编码
data = bytes(urllib.parse.urlencode({"word":"hello"}),encoding="utf8")
#打开指定需求爬取的网页
response = urllib.request.urlopen("http://httpbin.org/post",data=data)
html = response.read() #读取网页代码
print(html) #打印读取内容
2.urllib3模块
urllib3是一个功能强大、条理清晰、用于HTTP客户端的Python库,许多Python的原生系统已经开始使用urllib3。它提供了很多python标准库里没有的重要特性:
* 线程安全
* 连接池
* 客户端SSL/TLS验证
* 使用多部分编码上传文件
* Helpers 用于重试请求并处理HTTP重定向
* 支持gzip和deflate编码
* 支持HTTP和SOCKS代理
* 100%的测试覆盖率
通过urllib3模块实现发送网络请求的示例如下:
#urllib3 示例
import urllib3
#创建PoolManager对象,用于处理与线程池的连接以及线程安全的所有细节
http = urllib3.PoolManager()
#对需要爬取的网页发送请求
response = http.request("GET","https://www.baidu.com")
print(response.data) #打印读取内容
#发送post请求
response = http.request("POST","http://httpbin.org/post",fields={"word":"hello"})
print(response.data)
3.requests模块
requests是Python中实现HTTP请求的一种方式,requests是第三方模块,该模块在实现HTTP请深圳市时要比urllib模块简化很多,操作更加人性化。在使用requests模块时需要通过执行pip install requests代码进行该模块的安装。requests功能特性如下:
* Keep-Alive&连接池 * Unicode 响应体
* 国际化哉名和URL * HTTP(S)代理支持
* 带持久 Cookie的会话 * 文件分块上传
* 浏览器式的SSL认证 * 流下载
* 自动内容解码 * 连接超时
* 基本/摘要式的身份认证 * 分块请求
* 优雅的key/value Cookie * 支持.netrc
* 自动解压
以GET请求方式为例,打印多种请深圳市信息的示例代码如下:
#requests示例
import requests #导入模块
response = requests.get("http://www.baidu.com")
print(response.status_code) #打印状态码
print(response.url) #打印请求URL
print(response.headers) #打印头部信息
print(response.cookies) #打印cookie信息
print(response.text) #以文本形式打印网页源码
print(response.content) #以字节流形式打印网页源码
以POST请深圳市方式,发送HTTP网络请求的示例代码如下:
import requests
data = {"word":"hello"} #表单参数
#对需要爬取的网页发送请深圳市
reponse = request.pos("http://httpbin.org/post",data=data)
print(reponse.content) #以字节流形式打印网页源码
request模块不仅提供了以上两种常用的请求方式。还提供了以下多种网络请求的方式。
requests.put("http://httpbin.org/put",data={"key":"value"}) #PUT请求
requests.delete("http://httpbin.org/delete") #DELETE请求
requests.head("http://httpbin.org/get") #HEAD请求
requests.options("http://httpbin.org/get") #OPTIONS请求
如果发现请求的URL地址中参数是跟在?号的后面,例如:httpbin.org/get?key=val.Requests模块提供了传 递参数的方法,允许使用 params关键字参数,以一个字符串字典来提供这些参数。例如:想传 递 "key1=value1"和"key2=value2"到"httpbin.org/get",那可以使用如下代码:
import requests
payload = {"key1":"value1","key2":"value2"} #传递的参数
#对需要爬取的网页发送请求
response = requests.get("http://httpbin.org/get",params=payload)
print(response.content) #以字节流形式打印网页源码
2.2 请求headers处理
有时在请求一个网页内容时,发现无论通过GET还是POST以及其他请求方式,都会出现403错误,这种现象多数是由于服务器拒绝了您的访问,那是因为这些网页为了防止恶意采集信息,使用了反爬虫设置。此时可以通过模拟浏览器的头部信息来进行访问,这样就能解决以上反爬设置的问题。下面以requests模块为例介绍请求头部header的处理。
(1)通过浏览器的网络监视器查看头部信息,首先通过火狐浏览器打开对应的网页地址,然后快捷键F12打开网络监视 器,再刷新当前页面。
(2)选中第一条信息,右侧的消息头面板中将显示请求头部信息,复制该信息
(3)实现代码,首先创建一个需要爬取的URL地址,然后创建header头部信息,再发送请求等待响应,最后打印网页的代码信息。
import requests
url = "https://www.baidu.com"
#创建头部信息
headers = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:109.0) Gecko/20100101 Firefox/114.0"}
response = requests.get(url,headers=headers) #发送网络请求
pring(resonse.content) #以字节流形式打印网页源码
2.3 网络超时
在访问一个网页时,如果该网页长时间未响应,系统就会判断该网页超时,所以无法打开网页,看下面示例:
import requests
#循环发送请求50次
for a in range(1,50):
try:
#设置超时为0.5秒
response = requests.get("https://www.baidu.com/",timeout=0.1)
print(response.status_code) #打印状态码
except Exception as e: #捕范异常
print("异常:"+str(e)) #打印异常信息
运行结果如下图:
requests模块提供了三种常见的网络异常类。
#模拟访问超时
import requests
from requests.exceptions import ReadTimeout,HTTPError,RequestException
#循环发送请求50次
for a in range(1,50):
try:
#设置超时为0.1秒
response = requests.get("https://www.baidu.com/",timeout=0.1)
print(response.status_code) #打印状态码
except ReadTimeout: #超时异常
print("timeout")
except HTTPError: #HTTP异常
print("httperror")
except RequestException: #请求异常
print("reqerror")
2.4 代理服务
在爬取网页的过程中,经常会出现不及前可以爬取的网页现在无法爬取了,这是因为你的IP被目标网站屏蔽了。此时代理服务可以解决这一问题,设置代理时,首先要找到代理地址和端口号,比如:“122.114.31.177:808".
示例:
import requests
proxy = {"http":"122.114.31.177:808","http":"122.114.31.177:808"} #设置代理IP与对应的端口号
response = requests.get("http://www.mingrisoft.com",proxis=proxy)
print(response.content) #以字节流形式打印网页源码
三,网络爬虫的框架
3.1 常用的几个爬虫框架
Scrapy框架:它是一套比较成熟的Python爬虫框架。简单轻巧,并且非常方便,可以高校率的爬取Web页面并从页面中提取结构化的数据。
Crawley 爬虫框架:该框架致力于改变人们从互联网中提取数据的方式,具体特性如下:
* 基于Eventlet构建高速网络爬虫框架
* 可以将数据存储在关系数据库中,如Postgres、Mysql、Oracle、Sqlite
* 可以将爬取的数据导入为JSON,XML格式
* 支持非关系型数据库,比如Mongodb和Couchdb
* 支持命令行工具
* 可以使用喜欢的工具进行数据的提取,例如:XPath或Pyquery工具
* 支持使用Cookie登录或访问那些只有登录才可以访问的网页
PySpider 爬虫框架:它采用Python语言编写,分布式架构,支持多种数据库后端,强大的WebUI支持脚本编辑器、任务监视器、项目管理器以及结果查看器,其特性如下:
* Python 脚本控制,可以用任何你喜欢的html解析包(内置pyquery)
* Web界面编写调试脚本、起停脚本、监控执行状态等
* 支持Mysql、Mongodb、REDIS、SQLite、Elasticsearch、PostgreSSQL与SQLAlchemy
* 支持RabbitMQ、Beanstalk、Redis和Kombu作为消息队列
* 支持抓取JavaScript的页面
* 强大的调度控制,支持超时重爬及优先级设置
* 组件可替换,支持单机/分布式部署,支持Docker部署
3.2 Scrapy框架的应用
1.搭建Scrapy框架
1.1 首先安装twirsted依赖,步骤如下:
1).打开https://www.lfd.uci.edu/~gohlke/pythonlibs/ 搜索twisted
2).根据你的Python版本选择相应的twisted版本,我的Python3.8,所以下载Twisted-20.3.0-cp38-cp38-win_amd64.whl cp38对应的就是python3.8 , amd64 表示64位系统,如果你是32位系统就下载安装32位的软件
3).在此软件目录下执行: pip install Twisted-20.3.0-cp38-cp38-win_amd64.whl
1.2 安装Scrapy框架
执行: pip install Scrapy
1.3 安装pywin32模块
扫行:pip install pywin32
2.创建Scrapy项目
在任意目录下创建保存项目的文件夹,取名比如叫做:scrapyproject
在此目录下执行 scrapy startproject scrapydemo
会产生如下的初始结构:可以使用IDEA或其它开发工具打开
3.创建爬虫
下面通过一个示例来演示如何创建爬虫。
在spiders模块中创建quotes.py文件,编写如下代码:
#演示爬虫示例
import scrapy #导入框架
class QuotesSpider(scrapy.Spider):
name = "quotes" #定义爬虫名称
def start_requests(self):
#设置爬取目标的地址
urls =[
"http://quotes.toscrape.com/page/1/",
"http://quotes.toscrape.com/page/2/"
]
#获取所有地址,有几个地址发送几次请求
for url in urls:
#发送网络请求
yield scrapy.Request(url=url,callback=self.parse)
def parse(self,response):
#获取页数
page = response.url.split("/")[-2]
#根据页数设置文件名称
filename = "quotes-%s.html" % page
#写入文件的模块打开文件,如果没有该文件将创建该文件
with open(filename,"wb") as f:
#向文件中写入获取的html代码
f.write(response.body)
self.log("Saved file %s" % filename)
在IDEA中打开下面的 Terminal命窗口,输入: scrapy crawl quotes 来执行爬虫应用程序
爬虫开始爬取指定列表中的网页内容,并将其保存到html页面中去。
除了使用在命令窗口中输入命令"scrapy crawl quotes"外,也可以在程序中通过API来启动爬虫,这就是CrawlerProcess类,下面示例如下:
#演示爬虫示例
import scrapy #导入框架
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
class QuotesSpider(scrapy.Spider):
name = "quotes" #定义爬虫名称
def start_requests(self):
#设置爬取目标的地址
urls =[
"http://quotes.toscrape.com/page/1/",
"http://quotes.toscrape.com/page/2/"
]
#获取所有地址,有几个地址发送几次请求
for url in urls:
#发送网络请求
yield scrapy.Request(url=url,callback=self.parse)
def parse(self,response):
#获取页数
page = response.url.split("/")[-2]
#根据页数设置文件名称
filename = "quotes-%s.html" % page
#写入文件的模块打开文件,如果没有该文件将创建该文件
with open(filename,"wb") as f:
#向文件中写入获取的html代码
f.write(response.body)
self.log("Saved file %s" % filename)
#程序入口
if __name__ =="__main__":
#创建CrawlerProcess类对象并传入项目设置信息参数
process = CrawlerProcess(get_project_settings())
#设置需要启的爬虫名称
process.crawl("quotes")
#启动爬虫
process.start()
4.获取数据
scrapy爬虫框架,可以通过特定的CSS或者XPATH表达式来选择HTML文件中的某一处,并且提取出相应的数据,CSS(层叠样式表)用于控制HTML页面布局、字体、颜色、背景以及其他效果。XPath是一门可以在XML文档中,根据元素和属性查找信息的语言。
4.1 CSS提取数据
使用CSS提取HTML 文件中的某一处数据时,可以指定HTML文件中的标签名称,例如,获取上述案例中网页的title标签代码时,可以使用如下代码:
response.css("title").extract()
返回的内容是HTML标签列表:
['<title>Quotes to Scrape</title>']
想要提取列表时,可以使用下述代码:
response.css("title:text").extract_first()
或者
response.css("title:text")[0].extract
提取标签的内容为:
Quotes to Scrape
4.2 XPath提取数据
使用XPath表达式提取HTML文件中的某一处数据时,需要根据XPath表达式的语法规定来获取拽定的数据信息,如同样获取title标签内的信息时,可以使用如下代码:
response.xpath("//title/text()").extract_first(0)
示例:
#演示XPath提取数据
import scrapy #导入框架
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
class QuotesSpider(scrapy.Spider):
name = "quotes" #定义爬虫名称
def start_requests(self):
#设置爬取目标的地址
urls =[
"http://quotes.toscrape.com/page/1/",
"http://quotes.toscrape.com/page/2/"
]
#获取所有地址,有几个地址发送几次请求
for url in urls:
#发送网络请求
yield scrapy.Request(url=url,callback=self.parse)
def parse(self,response):
for quote in response.xpath(".//*[@class='quote']"):
#获取名人名言文字信息
text = quote.xpath(".//*[@class='text']/text()").extract_first()
#获取作者
author = quote.xpath(".//*[@class='author']/text()").extract_first()
#获取标签
tags = quote.xpath(".//*[@class='tag']/text()").extract()
#以字典形式输出信息
print(dict(text=text,author=author,tags=tags))
#程序入口
if __name__ =="__main__":
#创建CrawlerProcess类对象并传入项目设置信息参数
process = CrawlerProcess(get_project_settings())
#设置需要启的爬虫名称
process.crawl("quotes")
#启动爬虫
process.start()
4.3 翻页提取数据
以上示例中已经实现了获取网页中的数据,如果需要获取整个网页所有信息就需要使用到翻页功能,示例如下:
#演示翻页提取数据
import scrapy #导入框架
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
class QuotesSpider(scrapy.Spider):
name = "quotes" #定义爬虫名称
def start_requests(self):
#设置爬取目标的地址
urls =[
"http://quotes.toscrape.com/page/1/",
"http://quotes.toscrape.com/page/2/"
]
#获取所有地址,有几个地址发送几次请求
for url in urls:
#发送网络请求
yield scrapy.Request(url=url,callback=self.parse)
def parse(self,response):
for quote in response.xpath(".//*[@class='quote']"):
#获取作者
author = quote.xpath(".//*[@class='author']/text()").extract_first()
#输出作者
print(author)
#实现翻页
for href in response.css("li.next a::attr('href')"):
yield response.follow(href,self.parse)
#程序入口
if __name__ =="__main__":
#创建CrawlerProcess类对象并传入项目设置信息参数
process = CrawlerProcess(get_project_settings())
#设置需要启的爬虫名称
process.crawl("quotes")
#启动爬虫
process.start()
4.4 创建Items来保存数据
将上述案例中提取的text、author 以及tags信息保存在Item类中,本项目在创建时已经初始化一个Item.py,修改增加一些字段。
import scrapy
class ScrapydemoItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
#定义获取名人名言文字信息
text = scrapy.Field()
#定义获取的作者
author = scrapy.Field()
#定义获取的标签
tags = scrapy.Field()
Item创建完成后,修改自己完成的爬虫代码,在parse()方法中创建Item对象,然后输出item信息。
#演示Item封装提取数据
import scrapy #导入框架
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from scrapydemo.items import ScrapydemoItem
class QuotesSpider(scrapy.Spider):
name = "quotes" #定义爬虫名称
def start_requests(self):
#设置爬取目标的地址
urls =[
"http://quotes.toscrape.com/page/1/",
"http://quotes.toscrape.com/page/2/"
]
#获取所有地址,有几个地址发送几次请求
for url in urls:
#发送网络请求
yield scrapy.Request(url=url,callback=self.parse)
def parse(self,response):
for quote in response.xpath(".//*[@class='quote']"):
#获取名人名言文字信息
text = quote.xpath(".//*[@class='text']/text()").extract_first()
#获取作者
author = quote.xpath(".//*[@class='author']/text()").extract_first()
#获取标签
tags = quote.xpath(".//*[@class='tag']/text()").extract()
#创建Item对象
item = ScrapydemoItem(text=text,author=author,tags=tags)
yield item #输出信息
#程序入口
if __name__ =="__main__":
#创建CrawlerProcess类对象并传入项目设置信息参数
process = CrawlerProcess(get_project_settings())
#设置需要启的爬虫名称
process.crawl("quotes")
#启动爬虫
process.start()
四,相关作品展示
基于Java开发、Python开发、PHP开发、C#开发等相关语言开发的实战项目
基于Nodejs、Vue等前端技术开发的前端实战项目
基于微信小程序和安卓APP应用开发的相关作品
基于51单片机等嵌入式物联网开发应用
基于各类算法实现的AI智能应用
基于大数据实现的各类数据管理和推荐系统