Python学习-网络爬虫(一)

0x00 前言

一直都听说过网络爬虫,网络爬虫到底是什么?带着这个问题,我开始学习编写网络爬虫。下面记录了我学习过程中遇到的网络爬虫相关知识:

0x01 爬虫基本原理

1、爬虫概述

1.1 网络爬虫是什么?
网络爬虫是请求网站并提取数据的自动化程序。
网络爬虫有很多类型,常用的有通用网络爬虫、聚焦网络爬虫等。
1.2 爬虫基本流程

  1. 发起请求:通过HTTP库向目标站点发起请求,即发送一个Request,请求可以包含额外的headers等信息,等待服务器响应。
  2. 获取响应内容:如果服务器能正常响应,会得到一个Response,Response的内容便是所要获取的页面内容,类型可能有HTML, Json字符串,二进制数据(如图片视频)等类型。
  3. 解析内容:得到的内容可能是HTML,可以用正则表达式、网页解析库进行解析。可能是Json, 可以直接转为Json对象解析,可能是二进制数据,可以做保存或者进一步的处理。
  4. 保存数据:保存形式多样,可以存为文本,也可以保存至数据库,或者保存特定格式的文件。

1.3 能抓取怎样的数据?

  1. 网页文本:如HTML文档、Json格式文本等。
  2. 图片:获取到的是二进制文件,保存为图片格式。
  3. 视频:同为二进制文件,保存为视频格式即可。
  4. 其他:只要是能请求到的,都能获取。

2、爬虫基本流程的实现

2.1 Request

  1. 请求方式:主要有GET、POST两种类型,另外还有HEAD、PUT、DELETE、OPTIONS等。
  2. 请求URL:URL全称统一资源定位符, 如一个网页文档、一张图片、一个视频等都可以用URL唯一来确定。
  3. 请求头:包含请求时的头部信息,如User-Agent、 Host、Cookies等信息。
  4. 请求体:请求时额外携带的数据如表单提交时的表单数据。

2.2 Response

  1. 响应状态:有多种响应状态,如200代表成功、301跳转、404找不到页面、502服务器错误等。
  2. 响应头:如内容类型、内容长度、服务器信息、设置Cookie等等。
  3. 响应体:最主要的部分,包含了请求资源的内容,如网页HTML、图片二进制数据等。

2.3.1 怎样来解析?(解析方式)

  1. 直接处理
  2. Json解析
  3. 正则表达式
  4. 解析库(BeautifulSoup、PyQuery、Xpath)

2.3.2 怎样解决JavaScript渲染的问题?

  1. 分析Ajax请求
  2. Selenium/WebDriver
  3. Splash
  4. PyV8、Ghost.py

2.4 怎样保存数据?

  1. 文本:纯文本、Json、Xml等。
  2. 关系型数据库:如MySQL、Oracle、SQL Server等具有结构化表结构形式存储。
  3. 非关系型数据库:如MongoDB、Redis等Key-Value形式存储。
  4. 二进制文件:如图片、视频、音频等等直接保存成特定格式即可。

0x02 Python爬虫常用库

1.1 urllib

Python 内置的 HTTP 请求库,也就是说不需要额外安装即可使用。

  • urllib.request:请求模块,它是最基本的 HTTP 请求模块,可以用来模拟发送请求。
  • urllib.error:异常处理模块,如果出现请求错误,我们可以捕获这些异常,然后进行重试或其他操作以保证程序不会意外终止。
  • urllib.parse:url解析模块,提供了许多 URL 处理方法,比如拆分、解析、合并等。
  • urllib.robotparser:robots.txt解析模块,主要是用来识别网站的 robots.txt 文件,然后判断哪些网站可以爬,哪些网站不可以爬,用得比较少。

与Python2相比的变化

Python
import urllib2
response = urllib.urlopen('http://www.baidu.com')

Python3
import urllib.request
response = urllib.request.urlopen('http://www.baidu.com')

1.2 urllib基础操作

1.2.1 urlopen

urllib.request.urlopen(url,data=None,[timeout,]*,cafile=None,capath=None,cadefault=False,context=None)
get类型:
import urllib.request
response = urllib.request.urlopen('http://httpbin.org/get')
print(response.read().decode('utf-8'))

post类型:
import urllib.parse
import urllib.request
data = bytes(urllib.parse.urlencode({'word':'hello'}),encoding='utf8')
response = urllib.request.urlopen('http://httpbin.org/post',data=data)
print(response.read())

超时设置:
import socket
import urllib.request
import urllib.error
try:
    response = urllib.request.urlopen('http://httpbin.org/get',timeout=0.1)
except urllib.error.URLError as e:
    if isinstance(e.reason,socket.timeout):
        print('time out!')

1.2.2 响应
响应类型、状态码、响应头、响应内容:

import urllib.request
response = urllib.request.urlopen('http://www.baidu.com')
print(type(response)) #响应类型
print(response.status) #状态码
print(response.getheaders()) #响应头
print(response.getheader('Server')) #获取特定响应头
print(response.read().decode('utf-8') #响应内容

1.2.3 Request

urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)

url 用于请求 URL,这是必传参数,其他都是可选参数。
data 如果要传,必须传 bytes(字节流)类型的。如果是字典,可以先用urllib.parse模块里的 urlencode()编码。
headers 是一个字典,它就是请求头,在构造请求时通过headers参数直接构造,也可以通过调用请求实例的 add_header()方法添加。
添加请求头最常用的是通过修改User-Agent来伪装浏览器,默认的 User-Agent是 Python-urllib,我们可以通过修改它来伪装浏览器。比如要伪装火狐浏览器,你可以把它设置为:
Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11
origin_req_host 指的是请求方的 host 名称或者 IP 地址。
unverifiable 表示这个请求是否是无法验证的,默认是 False,意思就是说用户没有足够权限来选择接收这个请求的结果。例如,我们请求一个 HTML 文档中的图片,但是我们没有自动抓取图像的权限,这时 unverifiable 的值就是 True。
method 是一个字符串,用来指示请求使用的方法,比如 GET、POST 和 PUT 等。

get类型:
import urllib.request
request = urllib.request.Request('http://httpbin.org/get')
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))

post类型:
from urllib import request,parse
url = 'http://httpbin.org/post'
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0',
    'Host':'httpbin.org'
}
dict = {
    'name':'qwzf'
}
data = bytes(parse.urlencode(dict),encoding='utf8')
req = request.Request(url=url,data=data,headers=headers,method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))

另一种post:
from urllib import request,parse
url = 'http://httpbin.org/post'
dict = {
    'name':'qwzf'
}
data = bytes(parse.urlencode(dict),encoding='utf8')
req = request.Request(url=url,data=data,method='POST')
req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0)')
response = request.urlopen(req)
print(response.read().decode('utf-8'))

1.3 urllib高级操作

1.3.1 Handler
(1)代理
代理之前
在这里插入图片描述
打开控制面板->网络和 Internet->Internet选项->连接->局域网设置->代理服务器
在这里插入图片描述
看到系统代理端口为10809,然后使用代理软件开启代理服务即可。

from urllib.error import URLError
from urllib.request import ProxyHandler, build_opener

proxy_handler = ProxyHandler({
    'http': 'http://127.0.0.1:10809',
    'https': 'https://127.0.0.1:10809'
})
opener = build_opener(proxy_handler)
try:
    response = opener.open('http://httpbin.org/get')
    print(response.read().decode('utf-8'))
except URLError as e:
    print(e.reason)

代理成功
在这里插入图片描述
在这里插入图片描述
(2)Cookie

#cookie变量被赋值为请求地址的Cookie
import http.cookiejar, urllib.request
cookie = http.cookiejar.CookieJar()                 #声明CookieJar对象
handler = urllib.request.HTTPCookieProcessor(cookie)#构建处理Cookie
opener = urllib.request.build_opener(handler)       #build_opener传递Cookie
response = opener.open('http://www.baidu.com')
for item in cookie:                                 #打印Cookie信息
    print(item.name+"="+item.value)

在这里插入图片描述

#将请求地址的Cookie保存为文本文件
import http.cookiejar, urllib.request
filename = "cookie.txt"                             #将cookie保存成文本文件
#声明CookieJar对象的子类对象
#cookie = http.cookiejar.MozillaCookieJar(filename)  #声明MozillaCookieJar
cookie = http.cookiejar.LWPCookieJar(filename)      #声明LWPCookieJar
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True) #save()方法将Cookie保存成文本文件

在这里插入图片描述

#读取文本文件里存放的Cookie并附着在新的请求地址
import http.cookiejar, urllib.request
cookie = http.cookiejar.LWPCookieJar()
cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
print(response.read().decode('utf-8'))

1.3.2 异常处理
urllib.error异常类型:

  • URLError 属性:reason
  • HTTPError 属性:code、reason、headers
  • ContentTooShortError(msg,content)
from urllib import request, error
try:
    response = request.urlopen('http://www.httpbin.org/qwzf')
except error.HTTPError as e:
    print(e.reason, e.code, e.headers, sep='\n')
except error.URLError as e:
    print(e.reason)
else:
    print('Request Successfully')

在这里插入图片描述

import socket
import urllib.request
import urllib.error
try:
    response = urllib.request.urlopen('https://www.baidu.com', timeout=0.01)
except urllib.error.URLError as e:
    print(type(e.reason))
    if isinstance(e.reason, socket.timeout):
        print('TIME OUT')

在这里插入图片描述
1.3.3 URL解析
(1)urlparse
分隔url

urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)
#分隔url
from urllib.parse import urlparse
result = urlparse('http://www.baidu.com/index.html;user?id=5#comment')
print(type(result), result)
运行结果:
<class 'urllib.parse.ParseResult'> ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')


#指定以https解析
from urllib.parse import urlparse
result = urlparse('www.baidu.com/index.html;user?id=5#comment', scheme='https')
print(result)

#scheme作为默认,如果url指定解析方式,则scheme不生效
from urllib.parse import urlparse
result = urlparse('http://www.baidu.com/index.html;user?id=5#comment', scheme='https')
print(result)


from urllib.parse import urlparse
result1 = urlparse('http://www.baidu.com/index.html;user?id=5#comment', allow_fragments=False)
result2 = urlparse('http://www.baidu.com/index.html#comment', allow_fragments=False)
print(result1,'\n',result2)
运行结果:
ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5#comment', fragment='') 
ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html#comment', params='', query='', fragment='')

(2)urlunparse
拼接url

from urllib.parse import urlunparse
data = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment']
print(urlunparse(data))
运行结果:
http://www.baidu.com/index.html;user?a=6#comment

(3)urljoin
拼接url

from urllib.parse import urljoin
print(urljoin('http://www.baidu.com', 'FAQ.html'))
#后边url字段覆盖前面的url字段。
#前面有字段不存在,则补充。存在则覆盖
print(urljoin('http://www.baidu.com', 'https://cuiqingcai.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://cuiqingcai.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://cuiqingcai.com/FAQ.html?question=2'))
print(urljoin('http://www.baidu.com?wd=abc', 'https://cuiqingcai.com/index.php'))
print(urljoin('http://www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com#comment', '?category=2'))

在这里插入图片描述
(4)urlencode
把字典对象转换成get请求参数

from urllib.parse import urlencode
params = {
    'name': 'qwzf',
    'age': 20
}
base_url = 'http://www.baidu.com?'
url = base_url + urlencode(params)
print(url)

在这里插入图片描述

0x03 后记

本篇主要记录了爬虫的基本原理、urllib库和requests库的常见操作的学习与练习。Python网络爬虫学习持续更新中。。。。。。

发布了59 篇原创文章 · 获赞 29 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43625917/article/details/103998515
今日推荐