爬虫自学笔记(基础自看)【从入门到死亡】

Requests 库

anaconda自带requests库,如果使用其他IDE,可以以管理员身份打开cmd,输入pip install requests进行安装。安装后,import requests检查是否安装成功。

方法说明(括号内是HTTP协议对资源操作方法的说明)
requests.request()构造一个请求,支撑以下各方法的基础方法
requests.get()获取HTML网页的主要方法,对应于HTTP的GET(请求获取URL位置的资源)
requests.head()获取HTML网页的头信息的方法,对应于HTTP的HEAD(请求获取URL位置资源的响应消息报告,即获取该资源的头部信息)
requests.post()向HTML网页提交POST请求的方法,对应于HTTP的POST(请求向URL位置的资源后附加新的数据)
requests.put()向HTML网页提交PUT请求的方法,对应于HTTP的PUT(请求向URL位置存储一个资源,覆盖原URL位置的资源)
requests.patch()向HTML网页提交局部修改请求,对应于HTTP的PATCH(请求局部更新URL位置的资源,即改变该处资源的部分内容)
requests.delete()向HTML页面提交删除请求,对应于HTTP的DELETE(请求删除URL位置存储的资源)

requests.request()

requests.request(method,url,**kwargs)
“method”:请求方式,对应GET/HEAD/POST/PUT/PATCH/delete(小写!)/OPTIONS
“url”:拟获取页面的url连接
“**kwargs”:13个控制访问参数,可选

  • params: 字典或字节序列,作为参数增加到url中
kv={'key1':'value1','key2':'value2'}
r=requests.request('GET','http://python123.io/ws',params=kv)
print(r.url)
#https://python123.io/ws?key1=value1&key2=value2
  • data: 字典、字节序列或文件对象,作为Request的内容。向服务器提交资源时使用
kv={'key1':'value1','key2':'value2'}
r=requests.request('POST','http://python123.io/ws',data=kv)
body='主题内容'
r=requests.request('POST','http://python123.io/ws',data=body)
#data包含的内容作为url链接对应位置的数据存储
  • json: JSON格式的数据,作为Request的内容。作为内容向服务器提交。
  • headers: 字典,HTTP定制头
  • cookies: 字典或CookieJar, Request中的cookie
  • auth: 元组,支持HTTP认证功能
  • files: 字典类型,向服务器传输文件
  • timeout: 设定超时时间,秒为单位
  • proxies: 字典类型,设定访问代理服务器,可以增加登录认证
  • allow_redirects: True/False,默认为True,重定向开关
  • stream: True/False,默认为True,获取内容立即下载开关
  • verify: True/False,默认为True,认证SSL证书开关
  • cert: 保存本地SSL证书路径

requests.get()

requests.get(url,params=None,**kwargs)
“params”:url中的额外参数,字典或字节流格式,可选
“**kwargs”:12个控制访问参数(除了requests.request中的params)

r=requests.get(url) 构造一个向服务器请求资源的Request对象,并返回一个包含服务器资源的Response对象给“r”。Response对象有以下几个属性:

属性说明
r.status_codeHTTP请求的返回状态,200表示连接成功,404表示失败(只要不是200都表示失败)
r.textHTTP响应内容的字符串形式,即,url对应的页面内容
r.encoding从HTTP header中猜测的响应内容编码方式
r.apparent_encoding从内容中分析出的响应内容编码方式(备选编码方式)
r.contentHTTP响应内容的二进制形式(如果获得图片,图片资源以二进制存储,可以用r.content还原图片)

r.encoding:如果header中不存在charset,则认为编码为ISO-8859-1
r.apparent_encoding:根据网页内容分析的编码方式,相对来说比r.encoding更加准确

r=requests.get('https://www.bilibili.com/')
r.status-code
#200
r.encoding
#'utf-8'
r.apparent_encoding
#'utf-8'
r.encoding='utf-8'
r.text
#'<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><title>哔哩哔哩 (゜-゜)つロ 干杯~-bilibili</title>略其他

其他

  1. requests.head(url,**kwargs)

    **kwargs: 13个控制访问参数

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

    data&json: 就是上述控制参数的内容
    **kwargs: 11个控制访问参数

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

    **kwargs: 12个控制访问参数

  4. requests.patch(url,data=None,**kwargs)

    **kwargs: 12个控制访问参数

  5. requests.delete(url,**kwargs)

    **kwargs: 13个控制访问参数

Requests库6种常用连接异常

异常说明
requests.ConnectionError网络连接错误异常,如DNS查询失败,拒绝连接等(直接访问google主页就会出现这种异常)
requests.HTTPErrorHTTP错误异常
requests.URLRequiredURL缺失异常
requests.TooManyRedirects超过最大重定向(Redirect)次数,产生重定向异常(访问复杂连接时出现)(重定向大概就是由URL转移到新的位置的意思)
requests.ConnectTimeout连接远程服务器超时异常(连接过程的超时)
requests.Timeout请求URL超时,产生超时异常(发出URL到获得内容整个过程的超时)

另外,Response也提供了一种识别异常的方法
r.raise_for_status():如果不是200,产生异常requests.HTTPError。
因此使用这种识别方法就可以搭建爬取网页的通用代码框架,如下:

######通用代码框架#######
import requests
def getHTMLText(url):
    try:
        r=requests.get(url,timeout=30)
        r.raise_for_status()
        r.encoding=r.apparent_encoding
        return r.text
    except:
        return '产生异常'
######试验#######
if __name__=='__main__':
    url='http://www.bilibili.com'
    print(getHTMLText(url))
#正常输出
if __name__=='__main__':
    url='www.bilibili.com'
    print(getHTMLText(url))  
#产生异常  

Robots协议

Robots Exclusion Standard 网络爬虫排除标准:网站告知网络爬虫哪些页面可以抓取,哪些不行。
形式:在网站根目录下的robots.txt文件。
查看各网站Robots协议:url/robots.txt(nike的robots.txt确实很有趣)
具体可看什么是robots协议?robots.txt文件怎么写?

BeautifulSoup

BeautifulSoup对应一个HTML/XML文档的全部内容。
Beautiful Soup库解析器

解析器使用方法条件
bs4的HTML解析器BeautifulSoup(mk,‘html.parser’)安装bs4库
lxml的HTML解析器BeautifulSoup(mk,‘lxml’)pip install lxml
lxml的XML解析器BeautifulSoup(mk,‘xml’)pip install lxml
html5lib的解析器BeautifulSoup(mk,‘html5lib’)pip install html5lib

Beautiful Soup类的基本元素

基本元素说明
Tag标签,最基本的信息组织单元,分别用<>和</>表明开头和结尾
Name标签的名字,<p>…的名字是‘p’,格式:<tag>.name
Attributes标签的属性,字典形式组织,格式:<tag>.attrs
NavigableString标签内非属性字符串,<>…</>中字符串,格式:<tag>.string
Comment标签内字符串的注释部分,一种特殊的Comment类型
import requests
from bs4 import BeautifulSoup
r=requests.get('http://python123.io/ws/demo.html')
demo=r.text
soup=BeautifulSoup(demo,'html.parser')
print(soup.prettify())
'''
prettify()为HTML增加换行符,也可以的为每一个标签做处理
返回结果:
<html>
 <head>
  <title>
   This is a python demo page
  </title>
 </head>
 <body>
  <p class="title">
   <b>
    The demo python introduces several python courses.
   </b>
  </p>
  <p class="course">
   Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
   <a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">
    Basic Python
   </a>
   and
   <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">
    Advanced Python
   </a>
   .
  </p>
 </body>
</html>
'''
tag=soup.a#a链接标签内容,只能返回其中第一个
#<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>
tag.attrs#标签属性,字典
'''
{'href': 'http://www.icourse163.org/course/BIT-268001',
 'class': ['py1'],
 'id': 'link1'}
 '''
tag.string#返回非属性字符串/注释
#'Basic Python'

基于bs4库的HTML内容遍历方法

  • 标签树的下行遍历:从根节点向叶子节点遍历
属性说明
.contents子节点的列表,将<tag>所有子节点存入列表
.children自己点的迭代类型,与.contents类似,用于循环遍历子节点
.descendants子孙节点的迭代类型,包含所有子孙节点,用于循环遍历
soup.body.content
'''
返回列表形式
['\n',
 <p class="title"><b>The demo python introduces several python courses.</b></p>,
 '\n',
 <p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
 <a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a> and <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>.</p>,
 '\n']
 '''
 len(soup.body.contents) #5
 soup.body.contents[0]#'\n'
 
 ####遍历#####
 for child in soup.body.children(descendants):
 	print(child)
  • 标签树的上行遍历:从叶子节点向根节点遍历
属性说明
.parent节点的父亲标签
.parents节点先辈标签的迭代类型,用于循环遍历先辈节点
for parent in soup.a.parents:
    if parent is None:
        print(parent)
    else:
        print(parent.name)
'''
p
body
html
[document]
'''
  • 标签树的平行遍历:平级节点之间互相遍历

平行遍历需要发生在同一父节点下的各节点之间

属性说明
.next_sibling返回按照HTML文本顺序的下一个平行节点标签
.previous_sbling返回按照HTML文本顺序的上一个平行节点标签
.next_siblings迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
.previous_siblings迭代类型,返回按照HTML文本顺序的前续所有平行节点标签
soup.a.next_sibling
#' and '
 '''平行节点直接是存在NavigableString类型,获得的不一定是标签类型'''
 for sibling in soup.a.next_siblings(previous_siblings):
 	print(sibling)

在这里插入图片描述

基于bs4库的HTML内容查找方法

<>.find_all(name,attrs,recursive,string,**kwargs)(跟正则表达式一起)
返回一个列表类型,存储查找的结果
name:对标签名称的检索字符串
attrs:对标签属性值的检索字符串,可标注属性检索
recursive:是否对子孙全部检索,默认True
string:<>…</>中字符串区域的检索字符串

<>.find_all() [soup.find_all()] ⟺ \Longleftrightarrow <>()[soup()]

######打印所有标签######
for tag in soup.find_all(True):
	print(tag.name)
############提取HTML中所有URL链接##############
for link in soup.find_all('a'):
    print(link.get('href'))
#http://www.icourse163.org/course/BIT-268001
#http://www.icourse163.org/course/BIT-1001870001

正则表达式

正则表达式常用操作符

操作符说明实例
.表示任何单个字符
[ ]字符集,对单个字符给出取值范围[abc]表示a、b、c,[a-z]表示a到z单个字符
[^]非字符集,对单个字符给出排除范围[^abc]表示非a或b或c的单个字符
*前一个字符0次或无限次扩展abc*表示ab、abc、abcc、abccc等
+前一个字符1次或无限次扩展abc+表示abc、abcc、abccc等
?前一个字符0次或1次扩展abc?表示ab、abc
|左右表达式任意一个abc|def表示abc、def
{m}扩展前一个字符m次ab{2}c表示abbc
{m,n}扩展前一个字符m至n次(含n)ab{1,2}c表示abc,abbc
^匹配字符串开头^abc表示abc且在一个字符串的开头
$匹配字符串结尾abc$表示abc且在一个字符串的结尾
( )分组标记,内部只能使用 | 操作符(abc)表示abc,(abc|def)表示abc、def
\d数字,等价于[0-9]
\w单词字符,等价于[A-Za-z0-9_]

最小匹配操作符
Re库默认贪婪匹配

操作符说明
*?前一个字符0次或无限次扩展,最小匹配
+?前一个字符1次或无限次扩展,最小匹配
??前一个字符0次或1次扩展,最小匹配
{m,n}?扩展前一个字符m至n次(含n),最小匹配

实际上就是’?'前面操作符的最小匹配。相当于在原先操作上进行限制。

Re库

re库采用raw string 类型表示正则表达式,表示为:r’text’
raw string是不包含转义符的字符串。(转义符不被解释为转义符)
当正则表达式包含转义符时,使用raw string

Re库主要功能函数

函数说明
re.search()在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
re.match()从一个字符串的开始位置起匹配正则表达式,返回match对象
re.findall()搜索字符串,以列表类型返回全部能匹配的子串
re.split()将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
re.finditer()搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象(用于循环)
re.sub()在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串
  1. re.search(pattern,string,flags=0)

    pattern:正则表达式的字符串或原生字符串表示
    string:待匹配字符串
    flags:正则表达式使用时的控制标记

常用标记说明
re.I re.IGNORECASE忽略正则表达式的大小写,[A-Z]能够匹配小写字符
re.M re.MULTILINE正则表达式中的 ^ 操作符能够将给定字符串的每行当做匹配开始
re.S re.DOTALL正则表达式中 . 操作符能够匹配所有字符,默认匹配除换行外的所有字符
import re
match = re.search(r'[1-9]\d{5}','BIT 100081')
if match:
	print(match.group(0))#match 对象的使用
#100081
#match 输出‘<re.Match object; span=(4, 10), match='100081'>’
  1. re.match(pattern,string,flags=0)
import re
match = re.match(r'[1-9]\d{5}','BIT 100081')
if match:
	print(match.group(0))
#输出为空,因为match是从符合正则表达式的起始位置开始,而改字段起始不符合正则表达式
'''
match.group(0)会报错
所以在输出时最好使用if语句,排除‘空’的情况,防止报错
'''
import re
match = re.match(r'[1-9]\d{5}','100081 BIT')
if match:
	print(match.group(0))
#100081
  1. re.findall(pattern,string,flags=0)
import re
ls = re.findall(r'[1-9]\d{5}','BIT100081 TSU100084')
#['100081', '100084'] 与上述不同,返回一个列表
  1. re.split(pattern,string,maxsplit=0,flags=0)

    maxsplit:最大分割数,剩余部分作为最后一个元素输出

re.split(r'[1-9]\d{5}','BIT100081 TSU100084')
#['BIT', ' TSU', '']
#匹配的正则表达式去掉,剩下的部分分别作为字符串放入列表
re.split(r'[1-9]\d{5}','BIT100081 TSU100084',maxsplit=1)
#['BIT', ' TSU100084']
#只匹配第一个,剩下部分不再进行正则表达式匹配,以一个完整的部分作为列表最后部分
re.split(r'[1-9]\d{5}','BIT100081 TSU100084 BJF100083',maxsplit=1)
#['BIT', ' TSU100084 BJF100083']
  1. re.finditer(pattern,string,flags=0)
import re
for m in re.finditer(r'[1-9]\d{5}','BIT100081 TSU100084'):
	if m:
		print(m.group(0))
#100081
#100084
  1. re.sub(pattern,repl,string,count=0,flags=0)
    repl:替换匹配字符串的字符串
    count:匹配的最大替换次数
import re 
re.sub(r'[1-9]\d{5}',':zipcode','BIT100081 TSU100084')
#'BIT:zipcode TSU:zipcode'
re.sub(r'[1-9]\d{5}',':zipcode','BIT100081 TSU100084',count=1)
#'BIT:zipcode TSU100084'

Re库的等价用法

  1. 函数式用法:一次性操作

rst = re.search(r’[1-9]\d{5}’,‘100081 BIT’)

  1. 面向对象用法:编译后的多次操作

pat = re.compile(r’[1-9]\d{5}’)
rst = pat.search(‘100081 BIT’)

regex=re.compile(pattern,flags=0)
将正则表达式的字符串形式编译成正则表达式对象,regex就可以使用各种函数方法

Re库的Match对象

Match对象的属性

match=re.search(r’[1-9]\d{5}’,‘BIT 100081’)

属性说明
.string待匹配的文本 ‘BIT 100081’
.re匹配时使用的pattern对象(正则表达式) re.compile(r’[1-9]\d{5}’, re.UNICODE)
.pos正则表达式搜索文本的开始位置 0
.endpos正则表达式搜索文本的结束位置 10

Match对象的方法

方法说明
.group(0)获得匹配后的字符串 ‘100081’
.start()匹配字符串在原始字符串的开始位置 4
.end()匹配字符串在原始字符串的结束位置 10
.span()返回(.start(0,.end()) (4, 10)

Scrapy

重新开了一篇,Scrapy会不断往里面加东西。
(逐渐开始套娃)

使用fake-useragent对User-Agent进行伪装

pip install fake-useragent#安装
from fake_useragent import UserAgent
ua=UserAgent()
#这个时候可能报错
#“fake_useragent.errors.FakeUserAgentError: Maximum amount of retries reached”
#只要“pip install -U fake-useragent”更新一下就可以
print(ua.random)
#Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:21.0) Gecko/20130331 Firefox/21.0
print(ua.random)
#Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2225.0 Safari/537.36

#使用时
headers={'User-Agent':str(ua.random)}
r=requests.get(url,headers=headers)

例子

获取图片/视频

import requests
path='F:/abc.jpg'
url='http://img0.dili360.com/ga/M00/03/DB/wKgBzFRvBHyAdJRkAAaKCZvDQSA769.tub.jpg@!rw14'
r=requests.get(url)

with open(path,'wb') as f:#传入标识符'w'或者'wb'表示写文本文件或写二进制文件,读是'r'或'rb'
	f.write(r.content)
#在对应path位置已保存该图片
#可用if循环

中国大学排名定向爬虫

import requests
import bs4
from bs4 import BeautifulSoup

# 爬取网络信息,返回html信息
def getHTMLText(url):
    try:
        r=requests.get(url, timeout = 30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ''
    return ''

# 提取html关键数据,并添到一个列表中
def fillUnivList(ulist,html):
    soup=BeautifulSoup(html,'html.parser')
    for tr in soup.find('tbody').children:
        if isinstance(tr, bs4.element.Tag):#检测tr类型
            tds = tr('td')
            ulist.append([tds[0].string,tds[1].string,tds[3].string])

def printUnivList(ulist,num):
    tplt='{0:<10}\t{1:{3}<15}\t{2:<10}'#{3}是指填充时按照format[3]填充,即中文
    print(tplt.format('排名','学校名称','总分',chr(12288)))
    for i in range(num):
        u=ulist[i]
        print(tplt.format(u[0],u[1],u[2],chr(12288)))
    
def main():
    uinfo = []#大学信息
    url='http://www.zuihaodaxue.com/zuihaodaxuepaiming2019.html'
    html=getHTMLText(url)
    fillUnivList(uinfo,html)
    printUnivList(uinfo,20)# 20 univs

main()

股票数据定向爬虫

目标:获取上交所和深交所所有股票的名称和交易信息
输出:保存到文件中
选取网站原则:股票信息静态存在于HTML页面中,非js代码生成,没有Robots协议限制
使用网站:http://quote.eastmoney.com/stock_list.html & https://www.laohu8.com/stock

import requests
from bs4 import BeautifulSoup
import re
import traceback
from fake_useragent import UserAgent


def getHTMLText(url,headers):
    try:
        r = requests.get(url,headers=headers,timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ''

#输出股票列表和股票网站
def getStockList(lst,stockURL,headers):
    html = getHTMLText(stockURL,headers)
    soup = BeautifulSoup(html, 'html.parser')
    a = soup.find_all('a')
    for i in a:
        try:
            href = i.attrs['href']#获得href下内容
            lst.append(re.findall(r'[s][hz]\d{6}',href)[0])#本来返回一个列表,将内容提取出来再存放入列表
            #对于demo来说
            #re.findall(r'\d{6}',tag.attrs['href'])
            #['268001']
            # re.findall(r'\d{6}',tag.attrs['href'])[0]
            #'268001'
        except:
            continue


#获得个股信息
def getStockInfo(lst,stockURL,fpath,headers):
    for stock in lst:
        num = re.findall(r'\d{6}',stock)[0]
        url = stockURL + num
        html = getHTMLText(url, headers)
        try:
            if html == '':
                continue
            infoDict = {}
            soup = BeautifulSoup(html,'html.parser')
            stockInfo = soup.find('div',attrs={'class':'stock-main'})
            
            name = stockInfo.find_all(attrs={'class':'stock-name'})[0]
            infoDict.update({'股票名称':name.text.split()[0]})
            
            #所有信息分装在<dt>和<dd>中
            keyList = stockInfo.find_all('dt')
            valueList = stockInfo.find_all('dd')
            for i in range(len(keyList)):
                key = keyList[i].text
                val = valueList[i].text
                infoDict[key] = val
            with open(fpath,'a',encoding='utf-8') as f:
                f.write(str(infoDict)+'\n')
        except:
            traceback.print_exc()
            continue

def main():
    stock_list_url = 'http://quote.eastmoney.com/stock_list.html'
    stock_info_url = 'https://www.laohu8.com/stock/'
    output_file = 'F://LaoHuStockInfo.txt'
    slist = []#股票信息
    ua = UserAgent()
    header = {'User-Agent':str(ua.random)}
    getStockList(slist,stock_list_url,header)
    getStockInfo(slist,stock_info_url,output_file,header)
    
main()

结语

这一篇关于北理嵩天老师的爬虫笔记就结束辽。总的来说还是比较基础的视频,但是还是有很多内容需要我慢慢消化。然后就是踏上了自学之路。
笔记有一点乱,看的朋友多担待,大佬们有什么建议的欢迎来提啊,小白在这里先感谢一波!

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值