pip install requests
Requests库的安装测试:
>>> import requests
>>> r = requests.get("http://www.baidu.com")
>>> r.status_code
200
>>> r.encoding = 'utf-8' #修改默认编码
>>> r.text #打印网页内容
HTTP,Hypertext Transfer Protocol,超文本传输协议
HTTP是一个基于“请求与响应”模式的、无状态的应用层协议。
HTTP协议采用URL作为定位网络资源的标识。
URL格式:http://host[:port][path]
host:合法的Internet主机域名或IP地址
port:端口号,缺省端口为80
path:请求资源的路径
HTTP URL的理解:
URL是通过HTTP协议存取资源的Internet路径,一个URL对应一个数据资源。
HTTP协议对资源的操作:
方法 | 说明 |
---|---|
GET | 请求获取URL位置的资源 |
HEAD | 请求获取URl位置资源的响应消息报告,即获得该资源的头部信息 |
POST | 请求向URL位置的资源后附加新的数据 |
PUT | 请求向URL位置存储一个资源,覆盖原URL位置的资源 |
PATCH | 请求局部更新URL位置的资源,即改变该处资源的部分内容 |
DELETE | 请求删除URL位置存储的资源 |
方法 | 说明 |
---|---|
requests.request() | 构造一个请求,支撑以下各方法的基础方法 |
requests.get() | 获取HTML网页的主要方法,对应于HTTP的GET |
requests.head() | 获取HTML网页头信息的方法,对应于HTTP的HEAD |
requests.post() | 向HTML网页提交POST请求的方法,对应于HTTP的POST |
requests.put() | 向HTML网页提交PUT请求的方法,对应于HTTP的PUT |
requests.patch() | 向HTML网页提交局部修改请求,对应于HTTP的PATCH |
requests.delete() | 向HTML网页提交删除请求,对应于HTTP的DELETE |
主要方法为request方法,其余6个都是由request方法封装。
request()方法:
requests.request(method,url,**kwargs)
13个控制访问参数分别为:
get()方法:
requests.get(url,params=None,**kwargs)
该方法构造了一个向服务器请求资源的Request对象,返回了一个包含服务器资源的Response对象,Response对象包含爬虫返回的内容
Response对象的属性:
属性 | 说明 |
---|---|
r.status_code | HTTP请求的返回状态,200表示连接成 |
r.text | HTTP响应内容的字符串形式,即:url对应的页面内容 |
r.encoding | 从HTTP header中猜测的响应内容编码方式 |
r.apparent_encoding | 从内容中分析出的响应内容编码方式(备选编码方式) |
r.content | HTTP响应内容的二进制形式 |
head()方法:
requests.head(url,**kwargs)
post()方法:
requests.post(url,data=None,json=None,**kwargs)
put()方法:
requests.put(url,data=None,json=None,**kwargs)
patch()方法:
同put()方法
delet()方法:
requests.delete(url,**kwargs)
Requests库的异常:
异常 | 说明 |
---|---|
requests.ConnectionError | 网络连接错误异常,如DNS查询失败、拒绝连接等 |
requests.HTTPError | HTTP错误异常 |
requests.URLRequired | URL缺失异常 |
requests.TooManyRedirects | 超过最大 重定向次数,产生重定向异常 |
requests.ConnectTimeout | 连接远程服务器超时异常 |
requests.Timeout | 请求URL超时,产生超时异常 |
r.raise_for_status() | 如果不是200产生异常requests.HTTPError |
import requests
def getHTMLText(url):
try:
r = requests.get(url,timeout=30)
r.raise_for_status() #如果不是200,引发HTTPError异常
r.encoding = r.apparent_encoding
return r.text
except:
return "产生异常"
if __name__ == "__main__":
url = "http://www.baidu.com"
print(getHTMLText(url))
向360搜索提交关键词:
import requests
# 向搜索引擎进行关键词提交
url = "http://www.so.com/s"
try:
kv = {'q':'python'}
r = requests.get(url,params =kv)
print(r.request.url)
r.raise_for_status()
print(len(r.text))
except:
print("产生异常")
获取网络图片及存储:
import requests
import os
url = "http://image.ngchina.com.cn/2015/0323/20150323111422966.jpg"
root = "D:/pics/"
path = root + url.split('/')[-1]
try:
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
r = requests.get(url)
with open(path,'wb') as f:
f.write(r.content) # r.content返回二进制内容
f.close()
print("文件保存成功")
else:
print("文件已存在")
except:
print("爬取失败")
可以用anaconda安装scrapy,打开anaconda prompt,输入以下代码
conda install scrapy
报错:
CondaError: Downloaded bytes did not match Content-Length
url: https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/win-64/pywin32-227-py37he774522_1.conda
target_path: E:\Anaconda3\pkgs\pywin32-227-py37he774522_1.conda
Content-Length: 5808297
downloaded bytes: 2653872
问题是用conda安装包的时候下载包的长度不够导致安装包不成功,原因一般是在下载的时候速度较慢,通过更新配置的清华镜像源成功解决,具体配置方法请参考:Anaconda 镜像使用帮助
Scrapy不是一个函数功能库,而是一个爬虫框架。
Scrapy爬虫框架介绍:
Scrapy爬虫框架解析:
Engine:不需要用户修改
Downloader:不需要用户修改
Scheduler:不需要用户修改
Downloader Middleware:用户可编写配置代码
Spider:需要用户编写配置代码
Item Pipelines:需要用户编写配置代码
Spider Middleware:用户可以编写配置代码
requests vs. Scrapy:
相同点:
不同点:
requests | Scrapy |
---|---|
页面级爬虫 | 网站级爬虫 |
功能库 | 框架 |
并发性考虑不足,性能较差 | 并发性好,性能较高 |
重点在于页面下载 | 重点在于爬虫结构 |
定制灵活 | 一般定制灵活,深度定制困难 |
上手十分简单 | 入门稍难 |
Scrapy命令行:
Scrapy是为持续运行设计的专业爬虫框架,提供操作的Scrapy命令行
Scrapy常用命令:
命令 | 说明 | 格式 |
---|---|---|
startproject | 创建一个新工程 | scrapy startproject |
genspider | 创建一个爬虫 | scrapy genspider [options] |
settings | 获得爬虫配置信息 | scrapy setting [options] |
crawl | 运行一个爬虫 | scrapy crawl |
list | 列出工程中所有爬虫 | scrapy list |
shell | 启动URL调试命令行 | scrapy shell [url] |
步骤1:建立一个Scrapy爬虫工程
打开cmd,输入以下命令在工程目录创建一个新的Scrapy工程,工程名为python123demo
生成的工程目录:
python123demo/ ----------------> 外层目录
spiders/ ----> Spiders代码模板目录(继承类)
步骤2:在工程中产生一个Scrapy爬虫
步骤3:配置产生的spider爬虫
修改D:\pycodes\python123demo\python123demo\spiders\demo.py文件
# -*- coding: utf-8 -*-
import scrapy
class DemoSpider(scrapy.Spider):
name = 'demo'
# allowed_domains = ['python123.io']
start_urls = ['http://python123.io/ws/demo.html']
def parse(self, response):
fname = response.url.split('/')[-1]
with open(fname, 'wb') as f:
f.write(response.body)
self.log('Save file %s.' % name)
demo.py代码的完整版本
import scrapy
class DemoSpider(scrapy.Spider):
name = "demo"
def start_requests(self):
urls = [
'http://python123.io/ws/demo.html'
]
for url in urls:
yield scrapy.Requests(url=url, callback=self.parse)
def parse(self, response):
fname = response.url.split('/')[-1]
with open(fname, 'wb') as f:
f.write(response.body)
self.log('Saved file %s.' % fname)
步骤4:运行爬虫,获取网页
打开cmd,输入以下命令运行爬虫
Scrapy爬虫的使用步骤:
Request类:
class scrapy.http.Request()
属性或方法 | 说明 |
---|---|
.url | Request对应的请求URL地址 |
.method | 对应的请求方法,’GET‘ ’POST‘等 |
.headers | 字典类型风格的请求头 |
.body | 请求内容主体,字符串类型 |
.meta | 用户添加的扩展信息,在Scrapy内部模块间传递信息使用 |
.copy() | 复制该请求 |
Response类:
class scrapy.http.Response()
属性或方法 | 说明 |
---|---|
.url | Response对应的URL地址 |
.status | HTTP状态码,默认是200 |
.headers | Response对应的头部信息 |
.body | Response对应的内容信息,字符串类型 |
.flags | 一组标记 |
.request | 产生Response类型对应的Request对象 |
.copy() | 复制该响应 |
Item类:
class scrapy.item.Item()
Scrapy爬虫支持多种HTML信息提取方法:
CSS Selector的基本使用:
CSS Selector由W3C组织维护并规范
功能描述:
步骤1:建立工程和Spider模板
步骤2:编写Spider
修改spider.stocks.py文件使其能够解析返回的信息
# -*- coding: utf-8 -*-
import scrapy
import re
class StocksSpider(scrapy.Spider):
name = "stocks"
start_urls = ['https://quote.eastmoney.com/stocklist.html']
def parse(self, response):
for href in response.css('a::attr(href)').extract():
try:
stock = re.findall(r"[s][hz]\d{6}", href)[0]
url = 'https://gupiao.baidu.com/stock/' + stock + '.html'
yield scrapy.Request(url, callback=self.parse_stock)
except:
continue
def parse_stock(self, response):
infoDict = {}
stockInfo = response.css('.stock-bets')
name = stockInfo.css('.bets-name').extract()[0]
keyList = stockInfo.css('dt').extract()
valueList = stockInfo.css('dd').extract()
for i in range(len(keyList)):
key = re.findall(r'>.*', keyList[i])[0][1:-5]
try:
val = re.findall(r'\d+\.?.*', valueList[i])[0][0:-5]
except:
val = '--'
infoDict[key]=val
infoDict.update(
{'股票名称': re.findall('\s.*\(',name)[0].split()[0] + \
re.findall('\>.*\<', name)[0][1:-1]})
yield infoDict
步骤3:编写Pipelines
修改pipelines.py
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
class BaidustocksPipeline(object):
def process_item(self, item, spider):
return item
class BaidustocksInfoPipeline(object):
def open_spider(self, spider):
self.f = open('BaiduStockInfo.txt', 'w')
def close_spider(self, spider):
self.f.close()
def process_item(self, item, spider):
try:
line = str(dict(item)) + '\n'
self.f.write(line)
except:
pass
return item
修改setting.py中的ITEM_PIPELINES使框架能找到我们新定义的类
# Configure item pipelines
# See https://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'BaiduStocks.pipelines.BaidustocksInfoPipeline': 300,
}
配置并发连接选项:
settings.py文件
选项 | 说明 |
---|---|
CONCURRENT_REQUESTS | Downloader最大并发请求下载数量,默认为32 |
CONCURRENT_ITEMS | Item Pipeline最大并发ITEM处理数量,默认为100 |
CONCURRENT_REQUESTS_PRE_DOMAIN | 每个目标域名最大的并发请求数量,默认为8 |
CONCURRENT_REQUESTS_PRE_IP | 每个目标IP最大的并发请求数量,默认为0,非0有效 |