Python网络爬虫Requests库和Scrapy库入门

目录

    • 1 Requests库入门
      • 1.1 Requests库安装
      • 1.2 HTTP协议
      • 1.3 Requests库方法
      • 1.4 爬取网页的通用代码框架
      • 1.5 Requests库实战
    • 2 Scrapy库入门
      • 2.1 Scrapy库安装
      • 2.2 Scrapy爬虫框架
      • 2.3 Request库和Scrapy爬虫的比较
      • 2.4 Scrapy爬虫的常用命令
      • 2.5 Scrapy爬虫的第一个实例
      • 2.6 Scrapy爬虫的基本使用
      • 2.7 Scrapy爬虫的数据类型
      • 2.8 Scrapy爬虫提取信息的方法
      • 2.9 股票数据Scrapy爬虫实例


1 Requests库入门

1.1 Requests库安装

pip install requests

Requests库的安装测试:

>>> import requests
>>> r = requests.get("http://www.baidu.com")
>>> r.status_code
200
>>> r.encoding = 'utf-8' #修改默认编码
>>> r.text		#打印网页内容

1.2 HTTP协议

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位置存储的资源

1.3 Requests库方法

方法 说明
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)

  • method:请求方式,对应get/put/post等7种
  • url:拟获取页面的url链接
  • **kwargs:控制访问的参数,共13个,均为可选项

13个控制访问参数分别为:

  1. params:字典或字节序列,作为参数增加到url中
  2. data:字典、字节序列或文件对象,作为Request的内容
  3. json:JSON格式的数据,作为Request的内容
  4. headers:字典,HTTP定制头
  5. cookies:字典或CookieJar,Request中的cookie
  6. auth:元祖,支持HTTP认证功能
  7. files:字典类型,传输文件
  8. timeout:设定超时时间,秒为单位
  9. proxies:字典类型,设定访问代理服务器,可以增加登录认证
  10. allow_redirects:True/False,默认为True,重定向开关
  11. stream:True/False,默认为True,获取内容立即下载开关
  12. verify:True/False,默认为True,认证SSL证书开关
  13. cert:本地SSL证书路径

get()方法:

requests.get(url,params=None,**kwargs)

  • url:拟获取页面的url链接
  • params:url中的额外参数,字典或字节流格式,可选
  • **kwargs:12个控制访问的参数

该方法构造了一个向服务器请求资源的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)

  • url:拟获取页面的url链接
  • **kwargs:13个控制访问的参数

post()方法:

requests.post(url,data=None,json=None,**kwargs)

  • url:拟更新页面的url链接
  • data:字典、字节序列或文件,Request的内容
  • json:JSON格式的数据,Request的内容
  • **kwargs:11个控制访问的参数

put()方法:

requests.put(url,data=None,json=None,**kwargs)

  • url:拟更新页面的url链接
  • data:字典、字节序列或文件,Request的内容
  • **kwargs:12个控制访问的参数

patch()方法:

同put()方法

delet()方法:

requests.delete(url,**kwargs)

  • url:拟删除页面的url链接
  • **kwargs:13个控制访问的参数

1.4 爬取网页的通用代码框架

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))

1.5 Requests库实战

向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("爬取失败")

2 Scrapy库入门

2.1 Scrapy库安装

可以用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 镜像使用帮助

2.2 Scrapy爬虫框架

Scrapy不是一个函数功能库,而是一个爬虫框架。

Scrapy爬虫框架介绍:

  1. 爬虫框架是实现爬虫功能的一个软件结构和功能组件集合。
  2. 爬虫框架是一个半成品,能够帮助用户实现专业网络爬虫。
    Python网络爬虫Requests库和Scrapy库入门_第1张图片

Scrapy爬虫框架解析:

Engine:不需要用户修改

  • 控制所有模块之间的数据流
  • 根据条件触发事件

Downloader:不需要用户修改

  • 根据请求下载网页

Scheduler:不需要用户修改

  • 对所有爬取请求进行调度管理

Downloader Middleware:用户可编写配置代码

  • 目的:实施Engine、Scheduler和Downloader之间进行用户可配置的控制
  • 功能:修改、丢弃、新增请求或响应

Spider:需要用户编写配置代码

  • 解析Downloader返回的响应(Response)
  • 产生爬取项(scraped item)
  • 产生额外的爬取请求(Request)

Item Pipelines:需要用户编写配置代码

  • 以流水线方式处理Spider产生的爬取项
  • 由一组操作顺序组成,类似流水线,每个操作是一个Item Pipeline类型
  • 可能操作包括:清理、检验、和查重爬取项中的HTML数据、将数据存储到数据库

Spider Middleware:用户可以编写配置代码

  • 目的:对请求和爬取项的再处理
  • 功能:修改、丢弃、新增请求或爬取项

2.3 Request库和Scrapy爬虫的比较

requests vs. Scrapy:

相同点:

  • 两者都可以进行页面请求和爬取,Python爬虫的两个重要技术路线
  • 两者可用性都好,文档丰富,入门简单
  • 两者都没有处理js、提交表单、应对验证码等功能(可扩展)

不同点:

requests Scrapy
页面级爬虫 网站级爬虫
功能库 框架
并发性考虑不足,性能较差 并发性好,性能较高
重点在于页面下载 重点在于爬虫结构
定制灵活 一般定制灵活,深度定制困难
上手十分简单 入门稍难

2.4 Scrapy爬虫的常用命令

Scrapy命令行:

Scrapy是为持续运行设计的专业爬虫框架,提供操作的Scrapy命令行

Scrapy常用命令:

命令 说明 格式
startproject 创建一个新工程 scrapy startproject [dir]
genspider 创建一个爬虫 scrapy genspider [options]
settings 获得爬虫配置信息 scrapy setting [options]
crawl 运行一个爬虫 scrapy crawl
list 列出工程中所有爬虫 scrapy list
shell 启动URL调试命令行 scrapy shell [url]

2.5 Scrapy爬虫的第一个实例

步骤1:建立一个Scrapy爬虫工程

打开cmd,输入以下命令在工程目录创建一个新的Scrapy工程,工程名为python123demo
Python网络爬虫Requests库和Scrapy库入门_第2张图片
生成的工程目录:

python123demo/ ----------------> 外层目录

  • scrapy.cfg ---------> 部署Scrapy爬虫的配置文件
  • python123demo/ ---------> Scrapy框架的用户自定义Python代码
    __init__.py ----> 初始化脚本
    items.py ----> Items代码模板(继承类)
    middlewares.py ----> Middlewares代码模板(继承类)
    pipelines.py ----> Pipelines代码模板(继承类)
    settings.py ----> Scrapy爬虫的配置文件

​ spiders/ ----> Spiders代码模板目录(继承类)

  • __init__.py --------> 初始文件,无需修改
  • __pycache__/ --------> 缓存目录,无需修改

步骤2:在工程中产生一个Scrapy爬虫

打开cmd,输入以下命令生成一个名为demo的爬虫
Python网络爬虫Requests库和Scrapy库入门_第3张图片

步骤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,输入以下命令运行爬虫
在这里插入图片描述

2.6 Scrapy爬虫的基本使用

Scrapy爬虫的使用步骤:

  • 步骤1:创建一个工程和Spider模板;
  • 步骤2:编写Spider;
  • 步骤3:编写Item Pipeline
  • 步骤4:优化配置策略

2.7 Scrapy爬虫的数据类型

Request类:

class scrapy.http.Request()

  • Request对象表示一个HTTP请求
  • 由Spider生成,由Downloader执行
属性或方法 说明
.url Request对应的请求URL地址
.method 对应的请求方法,’GET‘ ’POST‘等
.headers 字典类型风格的请求头
.body 请求内容主体,字符串类型
.meta 用户添加的扩展信息,在Scrapy内部模块间传递信息使用
.copy() 复制该请求

Response类:

class scrapy.http.Response()

  • Response对象表示一个HTTP响应
  • 由Downloader生成,由Spider处理
属性或方法 说明
.url Response对应的URL地址
.status HTTP状态码,默认是200
.headers Response对应的头部信息
.body Response对应的内容信息,字符串类型
.flags 一组标记
.request 产生Response类型对应的Request对象
.copy() 复制该响应

Item类:

class scrapy.item.Item()

  • Item对象表示一个从HTML页面中提取的信息内容
  • 由Spider生成,由Item Pipeline处理
  • Item类似字典类型,可以按照字典类型操作

2.8 Scrapy爬虫提取信息的方法

Scrapy爬虫支持多种HTML信息提取方法:

  • Beautiful Soup
  • lxml
  • re
  • XPath Selector
  • CSS Selector

CSS Selector的基本使用:
Python网络爬虫Requests库和Scrapy库入门_第4张图片
CSS Selector由W3C组织维护并规范

2.9 股票数据Scrapy爬虫实例

功能描述:

  • 技术路线:scrapy
  • 目标:获取上交所和深交所所有股票的名称和交易信息
  • 输出:保存到文件中

步骤1:建立工程和Spider模板

  • \>scrapy startproject BaiduStocks
  • \>cd BaiduStocks
  • \>scrapy genspider stocks baidu.com
  • 进一步修改spiders/stocks.py文件

步骤2:编写Spider

  • 配置stock.py文件
  • 修改对返回页面的处理
  • 修改对新增URL爬取请求的处理

修改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文件
  • 定义对爬取项(Scrapy Item)的处理类
  • 配置ITEM_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有效

你可能感兴趣的:(Python网络爬虫与信息提取,python)