爬虫基础学习
1.python常用爬虫库基本介绍
1.1urllib
- 基本介绍:不需要关心http协议本身甚至更底层的实现,仅需要填充url、请求头、请求体等信息便可以实现http请求的发送和响应。python2中,有urllib和urllib2,但在python3中,统一为urllib。
- 基本模块:request、error、parse、robotparse;
- 基本用法:
- urlopen
import urllib.request
response = urllib.request.urlopen("http://www.yah00.site")
print(response.read())
调用read方法可以得到响应的网页内容
status():返回http响应码;
getheaders():响应的http头信息;
getheader(params):指定响应头的键信息;
urlopen():通过传入指定的参数完成对http页面的请求;
urllib.request.urlopen(url,data=None,[timeout,]*,cafile=None,capath=None,cadefault=False,context=None)
import urllib.request
import urllib.parse
import ssl
ssl._create_default_https_context = ssl._create_unverified_context #设置全局取消证书验证
data = bytes(urllib.parse.urlencode({'name':'germey'}),encoding='utf-8')
response = urllib.request.urlopen('https://httpbin.org/post',data=data)
print(response.read().decode('utf-8'))
- Request:使用urlopen可以发起基本的请求,但是其几个简单的参数并不足以构建一个完整的请求。如需要向请求中添加Headers等信息,就得利用更强大的Request类来构建请求了。
urllib.request.Request(url,data=None,headers={},origin_req_host,unverifiable=False,method=None)
请求示例:
import urllib.request
from urllib import request,parse
import ssl
ssl._create_default_https_context = ssl._create_unverified_context #设置全局取消证书验证
url = 'https://www.httpbin.org/post'
headers = {
'User-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36'
}
dict = {
'name':'abc'
}
data = bytes(parse.urlencode(dict),encoding='utf-8')
req = urllib.request.Request(url=url,data=data,headers=headers,method='POST')
print(req)
response = request.urlopen(req)
print(response.read().decode('utf-8'))
- 高级用法:
- BaseHandler类:
- HTTPDefaultErrorHandler:处理http响应错误;
- HTTPRedirectHandler:处理重定向;
- HTTPCookieProcessor:处理Cookie;
- ProxyHandler:设置代理;
- HTTpPasswordMgr:用于管理密码,维护用户名与密码的对照表;
- HTTPBasicAuthHandler:用于管理认证;
- OpenerDirector:Opener;
用Handler类构建Opener类;
验证示例:
如:url='https://ssr3.scrape.center/'页面的认证:
这种情况表示网站使用了基本身份认证(HTTPBasicAccessAuthentication)
借助HTTPdsBasicAuthHandler模块就可以完成;
from urllib.request import HTTPPasswordMgrWithDefaultRealm,HTTPBasicAuthHandler,build_opener
from urllib.error import URLError
import ssl
ssl._create_default_https_context = ssl._create_unverified_context #设置全局取消证书验证
username = 'admin'
password = 'admin'
url = 'https://ssr3.scrape.center/'
p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None,url,username,password)
auth_handler = HTTPBasicAuthHandler(p)
opener = build_opener(auth_handler)
try:
result = opener.open(url)
html = result.read().decode('utf-8')
print(html)
except URLError as e:
print(e.reason)
- 代理
from urllib.error import URLError
from urllib.request import ProxyHandler,build_opener
proxyHandler = ProxyHandler({
'http':'127.0.0.1:8080',
'https':'127.0.0.1:8080'
})
opener = build_opener(proxyHandler)
try:
response = opener.open("https://www.baidu.com")
print(response.read().decode('utf-8'))
except URLError as e:
print(e.reason)
- Cookie:获取网站Cookie
import http.cookiejar,urllib.request
cookie = http.cookiejar.CookieJar()
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
for item in cookie:
print(item.name + "=" +item.value )
以文件格式输出:
import http.cookiejar,urllib.request
filename = 'cookie.txt'
cookie = http.cookiejar.MozillaCookieJar(filename)
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)

使用LWPCookieJar方法生成的cookie文件输出如下图所示:

- 处理异常
- URLError
- HTTPError
URLError会输出页面异常reason,如:NotFound;HTTPError则会输出reason、code和headers属性;
因为URLError是HTTPError的父类,所以可以选择先捕获子类的错误,再捕获父类的错误,所以异常的处理代码最好如下:
from urllib import request,error
try:
response = request.urlopen('http://www.cuiqingcai.com/404')
except error.HTTPError as e:
print(e.reason,e.code,e.headers,sep='\n')
except error.URLError as e:
print(e.reason)
else:
print('Successfully')
这样就可以先捕获到HTTPError,获取它的错误原因、状态码、请求头等信息。如果不是HTTPError,就会捕获URLError异常,输出错误原因。
有时候reson返回的不一定是字符串,也有可能是一个对象。这里需要针对该种情况做进一步的判断。
- 解析链接
parse模块定义了处理URL的标准接口,例如实现URL各部分的抽取、合并以及链接转换。它支持如下协议的URL处理:file、ftp、gopher、hdl、http、https、imap、mailto、mms、news、nntp、prospero、rsync、rtsp、rtspu、sftp、sip、sips、snews、svn、svn+ssh、telnet和wais。
- urlparse:该方法可以实现对URL的识别和分段;
from urllib.parse import urlparse
result = urlparse('http://www.baidu.com/index.html;user?id=5#comment')
print(type(result))
print(result)

urllib.parse.urlparse(urlstring,scheme='',allow_fragments=True)
- urlunparse:用于构造URL;
from urllib.parse import urlunparse data = ['https','www.baidu.com','index.html','user','a=6','comment'] print(urlunparse(data))
输出即一个完整的URL:https://www.baidu.com/index.html;user?a=6#comment
需要注意的是,这里的构造参数必须 为6个,否则会抛出异常。
- urlsplit
- urlunsplit
- urljoin
- urlencode
- parse_qs
- parse_qsl
- quote
- unquote
- 分析Robots协议
1.2 requests库
urllib在处理网页验证和Cookie时,需要写Opener类和Handler类来处理,相对来说麻烦些。另外实现POST、PUT等请求的写法时也不太方便。
为了方便实现这些操作,于是产生了更为强大的库:requests。在处理Cookie、登录验证、代理设置等操作时变得方便了许多。
import requests
headers = {
'User-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36'
}
url = 'http://ssr1.scrape.center'
r= requests.request('GET',url=url,headers=headers,timeout=None)
print(r.content) #以二进制的结果输出,可以爬取图片、音视频等;
print(r.text) #以字符串的形式输出,即爬取的图片、音视频等信息会出现乱码
print(r.json()) #如果爬到的数据是json格式的,可以直接用该种方式输出
print(r.cookies)
print(r.status_code)
print(r.headers)
print(r.url)
print(r.history)
exit() if not r.status_code == requests.codes.ok else print('Succssefully!')#如果请求失败,结束程序;请求成功,输出;
返回码和相应的查询条件:https://www.cnblogs.com/Wang-Y/p/9349339.html
文件上传的用法:
import requests
files = {'file':open('cookie.txt','rb')}
r = requests.post('https://www.httpbin.org/post',files=files,verify=False)
print(r.text)
处理认证的用法:
import requests
#基础认证
r = requests.get('https://ssr3.scrape.center/',auth=('admin','admin'))
print(r.status_code)
import requests
from requests_oauthlib import OAuth1
#Oauth1认证示例
url = 'https://api.twitter.com/1.1/account/verify_credentials.json'
auth = OAuth1('','','','')
requests.get(url,auth=auth)
Request
from requests import Request,Session
s = Session()
url = 'http://ssr.scrape.center/'
r = Request('GET',url)
prepped = s.prepare_request(r)
res = s.send(prepped)
print(res.text)
1.3 httpx
基本介绍:对于强制使用HTTP/2.0协议访问的网站,requests库和urllib库是不支持的,这种情况可以使用httpx或是hyper;
httpx安装:pip3 install 'httpx[http2]',安装httpx和依赖的模块;
基本使用:
import httpx client = httpx.Client(http2=True) url = 'https://spa16.scrape.center/' res = client.get(url) print(res.text)
2.python提取爬取网页的数据方法
2.1正则表达式
引用:import re
几种模式:
1.match
从字符串的起始位置匹配,如果不是起始位置匹配成功的话会返回None,re.match(pattern,string,flags=0)
import re str = 'single world ,single people' print(re.match(r'single',str)) #直接返回对象 <re.Match object; span=(0, 6), match='single'> print(re.match(r'single',str).group()) #返回匹配的内容 single print(re.match(r'people',str)) #返回None
2.search
扫描整个字符串并返回第一个成功的匹配,re.search(pattern,string,flags=0)
3.sub
替换匹配到的字符串,语法格式:re.sub(pattern,replace,string)
4.findall
查找匹配的全部内容,以列表的形式返回,re.findall(pattern,string,flags=0)
5.compile
编译正则表达式模式,返回一个对象,re.compile(pattern,flags=0)
flags 标志位参数:
- re.I(re.IGNORECASE) :使匹配对大小写不敏感
- re.L(re.LOCAL) :做本地化识别(locale-aware)匹配
- re.M(re.MULTILINE) :多行匹配,影响 ^ 和 $
- re.S(re.DOTALL) :使 . 匹配包括换行在内的所有字符
- re.U(re.UNICODE):根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
- re.X(re.VERBOSE):该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
3.对scrape.center的爬虫实例
代码如下:
功能说明,仅仅是将爬取到的内容在控制台进行输出,没有引用创建文件或目录。
# -*- coding: UTF-8 -*-
import logging
import re
import requests
import multiprocessing
logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s: %(message)s')
class test(object):
def __init__(self):
self.url = "https://ssr1.scrape.center/detail/"
self.headers = {
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36'
}
def detail_res(self,page):
url = self.url + str(page)
try:
res = requests.get(url)
if res.status_code == 200:
return res.content.decode()
else:
logging.error("%s error status code: %s",url,res.status_code)
except requests.RequestException:
logging.error('error request',url,exc_info=True)
def re_match(self,page_index):
content = self.detail_res(page=page_index)
src_pattern = re.compile(r'data-v-63864230="".*?src="(.*?)".*?class="cover">',re.S)
name_pattern = re.compile(r'<h2 data-v-63864230="" class="m-b-sm">(.*?)</h2></a>',re.S)
catogory_pattern = re.compile(r'<button data-v-7f856186.*?<span>(.*?)</span>',re.S)
published_pattern = re.compile(r'<span data-v-7f856186="">(.*?)</span>',re.S)
time_pattern = re.compile(r'<span data-v-7f856186="">(.*?)</span>',re.S)
introduction_pattern = re.compile(r'<p data-v-63864230="">\n(.*?)\n.*?</p>',re.S)
timeshown_pattern = re.compile(r'(\d{4}-\d{2}-\d{2})\s?上映',re.S)
src = re.search(src_pattern,content).group(1)
name = re.search(name_pattern,content).group(1)
catogory = re.findall(catogory_pattern,content)
published_area = re.search(published_pattern,content).group(1)
timeTotal = re.findall(time_pattern,content)[2]
introduction = re.search(introduction_pattern,content).group(1)
timeshown = re.search(timeshown_pattern,content).group(1) if re.search(timeshown_pattern,content) else None #增加这样的语法,以防在匹配的过程中没有匹配到内容
return {
'src':src,
'name':name,
'catogory':catogory,
'published_area':published_area,
'timeTotal':timeTotal,
'introduction':introduction,
'timeshown':timeshown
}
if __name__ =="__main__":
testDemo =test()
for i in range(1,102):
testDemo.re_match(page_index=i)
4.补充库
4.1 logging库
4.1.1介绍:
logging库是python内置的标准模块,主要用于输出运行日志,可以设置输出日志的登记、日志保存路径、日志输出格式等;
4.1.2 记录级别说明:
|
级别 |
级别数值 |
使用时机 |
|
DEBUG |
10 |
详细信息,常用于调试 |
|
INFO |
20 |
程序正常运行过程中产生的一些信息 |
|
WARNING |
30 |
警告用户,虽然程序还在正常工作,但有可能发生错误 |
|
ERROR |
40 |
由于更严重的问题,程序已不能执行一些功能了 |
|
CRITICAL |
50 |
严重错误,程序已不能继续运行 |
默认的日志级别是warning
5.1.3 基本使用
向控制台输出:
# -*- coding: UTF-8 -*-
import logging
# 默认的日志输出级别为warning
# 使用basicConfig()来指定日志输出级别
logging.basicConfig(level=logging.DEBUG)
logging.debug("This is debug info")
logging.info("This is info info")
logging.warning("This is warning info")
logging.error("This is error info")
logging.critical("This is critical info")
创建一个名为log1.txt的文件,并向其中输入日志信息
# -*- coding: UTF-8 -*-
import logging
logging.basicConfig(format="%(asctime)s %(levelname)s %(filename)s %(lineno)s %(message)s"filename="log1.txt", filemode="w", level=logging.DEBUG)
logging.debug("This is debug info")
logging.info("This is info info")
logging.warning("This is warning info")
logging.error("This is error info")
高级应用:
logging模块采用了模块化设计,主要包含四种组件:
Logger:记录器,提供应用程序代码能直接使用的接口;
Handler:处理器,将记录器产生的日志发送到目的地;
Filter:过滤器,提供更好的粒度控制,决定哪些日志会被输出;
Formatter:格式化器,设置日志内容的组成结构和消息字段

具体使用方式参考链接:https://blog.csdn.net/Daningliu/article/details/119684778
另外可参考:nb_log
4.2 python进程池
multiprocessing
进程池:
即创建指定数量的进程
如:
import multiprocessing pool = multiprocessing.Pool(5) res = pool.map(f,[1,2,3,4,5,6,7,8,9,10]) #f表示运行的函数 pool.closes
浙公网安备 33010602011771号