爬虫基础学习

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

 

 

 

 

 

 

 

 

 

 

 

posted @   Mu1tySp1ay  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示