【Python】爬虫-MOOC前三周

【Python】爬虫

第0周 前奏

导学

学习目的:掌握定向网络数据爬取和网页解析的基本能力
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

开发工具选择:

在这里插入图片描述
在这里插入图片描述

通用类型集成环境特点
IDLE适用于,Python入门,功能简单直接,300+代码以内
Sublime Text专为程序员开发的第三方专用编程工具,专业编程体验,多种编程风格,工具非注册免费使用
Wing公司维护,工具收费,调试功能丰富,版本控制,版本同步,适合多人共同开发
Visual Studio&PTVS微软公司维护,Win环境为主,调试功能丰富,
Eclipse开源IDE开发工具,需要有一定开发经验
Pycharm社区版免费,简单,集成度高,适合较复杂工程
科学计算,数据分析集成环境特点
Canopy公司维护,工具收费,支持近500个第三方库,适合科学计算领域应用开发
Anaconda开源免费,支持近800个第三方库

第一章 网络爬虫规则/信息提取

the website is the API

Requests库入门

import requests
r=requests.get("http://www.baidu.com")
r.status_code
r.encoding='utf-8'
r.text

在这里插入图片描述

get方法

在这里插入图片描述在这里插入图片描述

在这里插入图片描述在这里插入图片描述

encoding和apparentencoding
r.encoding:如果 header中不存在 charset,则认为编码为ISO-8859-1
r. apparent_encoding:根据网页内容分析出的编码方式  可以得到中文
print(r.encoding)→ISO-8859-1  
print(r.apparent_encoding)→utf-8
print(r.text)
通用代码框架

Requests库的异常
在这里插入图片描述通用代码框架,最大的作用是使得用户访问和爬取网页,变得更有效,变得更稳定,变得更可靠。

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
exceptreturn "产生异常"
if _name_="_main_":
	url="http://www.baidu.com"
	print(gethtmltext(url))
Http协议与Requests库的主要方法

在这里插入图片描述
HTTP协议
HTP, Hypertext Transfer Protocol,超文本传输协议。
HTTP是一个基于“请求与响应”模式的、无状态的应用层协议。
HTTP协议采用URL作为定位网络资源的标识。
URL格式:http://host[:port ] [ path ]
host:合法的 Internet主机域名或P地址
port:端号,缺省端囗为80
path:请求资源的路径
在这里插入图片描述在这里插入图片描述

理解 PATCH和PUT的区别

假设URL位置有一组数据 Userinfo,包括 Userid、 Username等20个字段。
需求:用户修改了 Username,其他不变。
采用 PATCH,仅向URL提交 Usernamel的局部更新请求
采用PUT,必须将所有20个字段一并提交到URL,未提交字段被删除。
PATCH:节省网络带宽

head()方法

在这里插入图片描述

POST()方法

在这里插入图片描述在这里插入图片描述

POST一个字典/键值对,会默认存储到一个表单的字段下。POST一个字符串,会自动编码为data
PUT方法类似于POST方法,一个表单,只是会覆盖掉原有数据。

主要方法解析

request
在这里插入图片描述
在这里插入图片描述params
在这里插入图片描述POST方法提交data,并不作为url链接,而是url链接所对应的位置的地方作为数据来存储。
data
在这里插入图片描述JSON
在这里插入图片描述headers,模拟浏览器

在这里插入图片描述Cookie
auth
在这里插入图片描述timeout
在这里插入图片描述files

在这里插入图片描述proxies:这样访问网页时,所使用的地址就是代理服务器的地址。有效防止爬虫的逆追踪。
在这里插入图片描述
alow_redirects:
stream:
verify:
cert
在这里插入图片描述
掌握params,data,json,headers
get方法。

网络爬虫 盗亦有道

在这里插入图片描述骚扰问题 法律风险 个人隐私

网络爬虫的限制

来源审查:判断Uer- Agenti进行限制
检查来访HTTP协议头的User-Agent域,只响应浏览器或友好爬虫的访问。
发布公告: Robots协议
告知所有爬虫网站的肥取策略,要求爬虫遵守。

Robots协议

在这里插入图片描述

Robots Exclusion Standard网络爬虫排除标准
作用:网站告知网络吧虫哪些页面可以抓取,哪些不行。
形式:在网站根目录下的 robots,txt文件。
在这里插入图片描述

Robots协议的遵守方式

网络爬虫:自动或人工识别 robots.txt,再进行内容爬取。
约束性: Robots协议是建议但非约束性,网络爬虫可以不遵守,但存在法律风险。
在这里插入图片描述类似人类的获取信息行为,访问量小,频率也小,可以不遵守。

爬虫实例

京东商品页面
import requests
url="https://item.jd.com/2967929.html"
try:
	r= requests.get(url)
	r.raise_for_status()
	r.encoding=r.apparent_encoding
	print(r.text[:1000])
except:
	print("爬取失败")
亚马逊反爬
r=requests.get("https://www.amazon.cn/gp/product/B01M8L5Z3Y")
r.status_code#503爬取失败
r.request.headers#现实python爬虫告诉服务器,自己user-agent是python-requests
kv={'user-agent':'Mozilla/5.0'}
r.requests.get(url,headers=kv)
import requests
url="https://www.amazon.cn/gp/product/b01m8l5z3y"
try:
	kv={'user-agent':'Mozilla/5.0'}
	r= requests.get(url, headers=kv)
	r.raise_for_status()
	r.encoding =r.apparent_encoding
	print(r.text[1000:2000])
except:
	print("爬取失败")
百度搜索关键词 params

搜索引擎关键词提交接口
百度的关键词接口
http://www.baidu.com/s?wd=keyword
360的关键词接口
http://www.s0.com/s?q=keyword

import requests
kv ={'wd': 'Python'}
r=requests.get("http://www.baidu.com/s,params=kv)
r.status_code
r.request.url#通过response对象中包含的request对象信息,看请求的url到底
#是什么,http://www.baidu.com/s?wd=Python	
len(r.text)#660000+字节长度

全代码:

import requests
keyword="python"
try:
	kv={'wd':keyword}#360搜索引擎的键值对的键由wd改为q
	r=requests.get('http://www.baidu.com/s',params=kv)
	print(r.request.url)
	r.raise_for_status()
	print(len(r.text))
except:
	print("爬取失败")
网络图片的爬取和存储

r请求,已经包含了图片,如何保存为二进制格式。
r.content表示返回内容的二进制形式

import requests
import os
url="http://image.nationalgeographic.com.cn/2017/0211/20170211061910157.jpg"
root="D://pics//"
path=root+url.split('/')[-1]# 斜线分隔,并[-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)
			f.close()
			print("文件保存成功")
	else:
		print("文件已经存在")
except:
	print("爬取失败")
IP地址归属地的自动查询

ip138查询
http://m.ip138.com/iplookup.asp?ip=ipaddress

import requests
url="http://m.ip138.com/iplookup.asp?ip="
try:
	r= requests.get(url+'202.204.80.112')
	r.raise_for_status()
	r.encoding =r.apparent_encoding
	print(r.text[-500:])
except:
	print("爬取失败")

在这里插入图片描述

第二周 网络爬虫信息提取

在这里插入图片描述

Beautiful Soup库学习

安装:pip install beautifulsoup4

from bs4 import BeautifulSoup
soup=BeautifulSoup ("<p>data</p>',html.parser')
import requests
r=requests.get('http://www.baidu.com')
demo=r.text
from bs4 import BeautifulSoup
soup=BeautifulSoup(demo,'html.parser')#给出demo,并给出解析demo的解释器
print(soup.prettify())


BeautifulSoup库基本元素

Beautiful Soup库是解析、遍历、维护“标签树”的功能库。
在这里插入图片描述属性是由键和值组成的结构。
在这里插入图片描述BeautifulSoup类,可以对应一个HTML/XML的文档的全部内容。
在这里插入图片描述五种解析器:
在这里插入图片描述
在这里插入图片描述demo:http://python123.io/ws/demo.html

from bs4 import BeautifulSoup
demo="http://python123.io/ws/demo.html"
soup=BeautifulSoup(demo,"html.parser")#soup变量就是解析后的demo页面
soup.title#得到了title标签
tag=soup.a
tag
#任何一个标签都可以通过soup.<tag>的方式获得
soup.a.name
soup.a.parent.parent.name
tag=soup.a
type(tag)#标签是标签类型,返回 <class 'bs4.element.Tag'>
soup.p.string#是navigablestring类型,返回标签内容
#!--xxxx--!的注释内容也可以通过.string获得。只是type为comment
type(tag.attrs)#标签属性是字典类型,返回<class 'dict'>
tag.attrs#获得a标签的全部属性字典,标签名字,属性名字,和属性的值	
tag.attrs['class']#获得class属性的值
tag.attrs['href']#链接属性

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

HTML是树形结构的基本信息
在这里插入图片描述三种遍历方法
在这里插入图片描述在这里插入图片描述.contents返回的是列表
子节点不仅包括标签结点,也包括字符串结点(如’\n’)。
也即尽管树形结构采用标签的形式来组织,但标签之间的NavigableString也构成了标签树的结点。(平行标签)

下行遍历
len(soup.body.contents)#body标签的全部子节点个数。返回5
soup.body.contents[1]

在这里插入图片描述

上行遍历

在这里插入图片描述

最高级标签的.parent是他自己

在这里插入图片描述

平行遍历

在这里插入图片描述平行遍历条件:同一个父亲结点。

在这里插入图片描述在这里插入图片描述

基于bs4库的HTML格式输出

如何让HTML页面更加友好的显示

print(soup.prettify())
print(soup.a.prettify())

注意bs4库将读入的任何HTML文件和字符串都变成了utf-8编码。python3可以友好展示。

信息组织和提取方法

信息标记的三种形式 XML,JSON,YAML

信息的标记:
标记后的信息可形成信息组织结构,增加了信息维度
标记后的信息可用于通信、存储或展示
标记的结构与信息一样具有重要价值
标记后的信息更利于程序理解和运用

XML: extensible Markup Language

扩展标记语言
在这里插入图片描述img是标签。src是属性。china.jpg是值。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

JSON:Javsscript Object Notation

javascript语言中对面向对象信息的表达形式
有类型的键值对key: value
在这里插入图片描述键值对中都需要增加双引号。表达他是字符串的形式。如果是一个数字,直接写数字即可。
如果多个值,采用方括号组织。
键值对多值用[,]组织。
在这里插入图片描述键值对嵌套用{,}

在这里插入图片描述
在这里插入图片描述

YAML YAML A’int Markup Language

在这里插入图片描述通过缩进表达所属关系。
在这里插入图片描述通过-表达并列关系

在这里插入图片描述
|表达整块数据 在这里插入图片描述
在这里插入图片描述

三种信息标记形式的比较

XML实例:大多数信息被标签占用
在这里插入图片描述JSON都需要双引号
在这里插入图片描述很简洁
在这里插入图片描述

语言类型特点用处
XML最早的通用信息标记语言,可扩展性好,但因为需要起始繁琐。Internet上的信息交互与传递。
JSON信息有类型,适合程序处理(Js),较XML简洁。移动应用云端和节点的信息通信,无注释。
YAML信息无类型,文本信息比例最高,可读性好。各类系统的配置文件,有注释易读。

信息提取的一般方法

方法一:完整解析信息的标记形式,再提取美键信息。

XML JSON YAML
需要标记解析器例如:bs4库的标签树遍历
优点:信息解析准确
缺点提取过程繁琐,速度慢。

方法二:无视标记形式,直接搜索关键信息。

搜索
对信息的文本查找函数即可。
优点:提取过程简洁,速度较快。
缺点:提取结果准确性与信息内容相关。

融合方法:结合形式解析与搜索方法,提取关键信息。
XML JSON YAML + 搜索
需要标记解析器及文本查拢函数。

在这里插入图片描述

实例:提取HTML中所有URL链接

find_all .get(‘href’)

from bs4 import BeautifulSoup
soup=BeautifulSoup(demo,'html.parser')
for link in soup.find_all('a'):
	print(link.get('href'))

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

name是标签名称,可以是一个列表
在这里插入图片描述

import re
for tag in soup.fing_all(re.compile('b')):#re.compile('b')表示正则匹配所有以b开头的标签
	print(tag.name)#返回b和body	
soup.find_all('p','course')#找含有属性为course的p标签
soup.find_all(id='link1')#找属性及其值分别对应为id=link1的标签
soup.find_all(string="Basic Python")#检索内容为Basic Python

在这里插入图片描述

< tag >()等价于. find_all()
soup()等价于soup.find_all()

实例1 中国大学排名爬虫

实例介绍

输入:大学排名URL链接
输出:大学排名信息的屏幕输出(排名,大学名称,总分)
技水路线: requests-bs4
定向爬虫:仅对输入URL进行吧取,不扩展爬取。

程序的结构设计

步骤1:从网络上获取大学排名网页内容
步骤2:提取网页内容中信息到合适的数据结构
步骤3:利用数据结构展示并输出结果

步骤1:从网络上获取大学排名网页内容
getHTMLText()
步骤2:提取网页内容中信息到合适的数据结构
fillUnivList()
步骤3:利用数据结构展示井输出结果
printUnivList()

编写

	try:
		r=requests.get(url)
		r.raise_for_status
		r.encoding=r.apparent_encoding
		return r.text
	except:
		return ""

def fillUnivList(ulist,html):
	soup=BeautifulSoup(html)  
	for tr in soup.find('tbody').children:
		if isinstance(tr,bs4.element.tag):
			tds=tr('td')
			ulist.append([tds[0].string,tds[1].string,tds[2].string])

def printUnivList(ulist,num):
	print("{:^10}\t{:^6}\t{:^10}".format("排名","学校名称","总分"))
	for i in range(num):
		u=ulist[i]
		print("{:^10}\t{:^6}\t{:^10}".format(u[0],u[1],u[2]))

def main():
	uinfo=[]
	url="https://www.shanghairanking.cn/rankings/bcur/2020"
	html=getHTMLText(url)
	fillUnivList(uinfo,html)
	printUnivList(uinfo,20)

main()

首先找到tbody标签,再在其中解析tr标签,再在tr中找到td标签
在这里插入图片描述

中英文混合输出需要注意对齐问题。

当空格不够,默认的是西文空格填充,而不是中文空格。
中文对齐的填充:
采用中文字符的空格填充 chr(12288)#utf-8编码的中文空格。
tplt="{0:^10}\t{1:{3}^10}\t{2:^10}" 使用tplt的{3}第三个变量进行填充。
print(tplt.format("排名","学校名称","总分",chr(12288))
print(tplr.format(t[0),t[1],t[2],chr(12288))

第三周 爬虫实战

Re(正则表达式)

regular expression regex RE
通用的字符串表达框架
简洁表达一组字符串的表达式
针对字符串表达“简洁”和“特征”思想的工具
判断某字符串的特征归属
在这里插入图片描述
在这里插入图片描述表达文本类型的特征(病毒、人侵等)
同时查找或替换一组字符串
匹配字符串的全部或部分

正则表达式的使用:
编译:将符合正则表达式语法的字符串转换成正则表达式特征。
编译后的特征与一组字符串是对应的。
在这里插入图片描述

正则表达式的语法

在这里插入图片描述

正则表达式常用操作符:

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

经典正则表达式实例

^表示以次开头,[]限定范围,+表示1-无限次拓展,$表示以次结尾,?表示0或1次拓展,*表示前一个字符0或无限次拓展,\d表示数字[0-9]

正则式含义
^ [A-Za-z]+$由26个字母组成的字符串
^ [A-Za-z0-9]+$由26个字母和数字组成的字符串
^-?\d$整数形式的字符串
^ [0-9 ]*[ 1-9 ] [0-9] *$正整数形式的字符串
[1-9]\d{5}中国境内邮政编码
[\u4e00-\u9fa5]匹配中文字符
\d{3}-\d{8}竖线\d{4}-\d{7}国内电话号码,010-68913536
匹配IP地址的正则表达式

IP地址字符串形式的正则表达式
(IP地址分4段,每段0-255)

#不太精确
\d+.\d+.\d+.\d+
\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}
#精确写法,将255拆分
0-99:[1-9]?\d 100-199:1\d{2}
200-249:2[0-4]\d 250-255:25[0-5]
([[1-9]?\d|1\d{2}|2[0-4]\d|25[0-5].]){3}([[1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]])

Re库的基本使用
正则表达式的表达类型:
  • raw string类型(原生字符串类型)raw string是不包含转义符的字符串,原生字符中间的\不被解释为转义字符
    re库采用 raw stringa类型表示正则表达式,表示为:r‘text’
    例如:r‘[1-9]\d{5}’
  • string类型,更繁琐。需要两个\
    当正则表达式包含《转义符》时使用 raw string
主要功能函数

re.search(),re.match(),re.findall(),re.split(),re.finditer(),re.sub()
在这里插入图片描述re.search(pattern,string,flag=0)
在这里插入图片描述
在这里插入图片描述
.match()是从起始位置开始匹配。
在这里插入图片描述要搭配if使用
re.findall()
在这里插入图片描述re.split()是按正则匹配,匹配的部分去掉,去掉后的东西放到一个列表里。
在这里插入图片描述在这里插入图片描述
re.finditer()
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

re库另一种等效用法:

将一个正则表达式的字符串编译为一个正则表达式的类型。patter对象。直接调用方法,获得结果。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Re库的match对象

在这里插入图片描述

Match对象的属性

在这里插入图片描述search()中.pos是0

Match对象的方法

在这里插入图片描述计算机内部认为经过compile的才是正则表达式。
在这里插入图片描述在这里插入图片描述

Re库的贪婪匹配和最小匹配

Re库默认贪婪匹配,如果有多个,则是最长匹配。
PY.*N
最短匹配
PY.*?N

在这里插入图片描述当有操作符可以匹配不同长度时,都可以在这个操作符后面添加一个?,来获得最小匹配的结果。
在这里插入图片描述

实例2 淘宝商品比较定向爬虫比较

介绍

功能描述:
目标:获取淘宝搜索页面的信息,提取其中的商品名称和价格。
理解:淘宝的搜索接口-翻页的处理
技术处理:requests-re
在这里插入图片描述观察分析:
在这里插入图片描述

程序的结构设计

步骤1:提交商品搜索请求,循环获取页面。
步骤2:对于每个页面,提取商品名称和价格信息。
步骤3:将信息输出到屏幕上。

编写
#CrowTaobaoPrice.py
import requests
import re

def getHTMLText(url):
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""
    
def parsePage(ilt, html):
    try:
    	#\ 这是引用符,用来将这里列出的这些元字符当作普通的字符来进行匹配。
    	#例如正则表达式\$被用来匹配美元符号
    	#商品价格由view_price这个键值对组成
        plt = re.findall(r'\"view_price\"\:\"[\d\.]*\"',html)
        tlt = re.findall(r'\"raw_title\"\:\".*?\"',html)
        for i in range(len(plt)):
            price = eval(plt[i].split(':')[1])
            title = eval(tlt[i].split(':')[1])
            ilt.append([price , title])
    except:
        print("")

def printGoodsList(ilt):
    tplt = "{:4}\t{:8}\t{:16}"
    #打印输出标题
    print(tplt.format("序号", "价格", "商品名称"))
    #count作为序号计数
    count = 0
    for g in ilt:
        count = count + 1
        print(tplt.format(count, g[0], g[1]))
        
def main():
    goods = '书包'
    depth = 3
    start_url = 'https://s.taobao.com/search?q=' + goods
    infoList = []
    for i in range(depth):
        try:
        	#观察到不同url中,s相差44
            url = start_url + '&s=' + str(44*i)
            html = getHTMLText(url)
            parsePage(infoList, html)
        except:
            continue
    printGoodsList(infoList)
    
main()

实例3 股票数据定向爬虫

功能描述
目标:获取上交所和深交所所有股票的名称和交易信息
输出:保存到文件中
技水路线: requests-bs4-re

要找那些信息写在HTML代码中

程序的结构设计

步骤1:从东方财富网获取股票列表
步骤2:根据股票列表逐个到百度股票获取个股信息
步骤3:将结果存储到文件

获得r.apparent_encoding较耗费时间。手动访问网页并赋值,
增加动态进度显示。
\r特殊的转义符,将光标提到头部。下一次打印就会覆盖展示。

#CrawBaiduStocksA.py
import requests
from bs4 import BeautifulSoup
import traceback
import re

def getHTMLText(url):
    try:
        r = requests.get(url)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""

def getStockList(lst, stockURL):
    html = getHTMLText(stockURL)
    soup = BeautifulSoup(html, 'html.parser') 
    a = soup.find_all('a')
    for i in a:
        try:
            href = i.attrs['href']
            lst.append(re.findall(r"[s][hz]\d{6}", href)[0])
        except:
            continue

def getStockInfo(lst, stockURL, fpath):
    for stock in lst:
        url = stockURL + stock + ".html"
        html = getHTMLText(url)
        try:
            if html=="":
                continue
            infoDict = {}
            soup = BeautifulSoup(html, 'html.parser')
            stockInfo = soup.find('div',attrs={'class':'stock-bets'})

            name = stockInfo.find_all(attrs={'class':'bets-name'})[0]
            infoDict.update({'股票名称': name.text.split()[0]})
            
            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 = 'https://quote.eastmoney.com/stocklist.html'
    stock_info_url = 'https://gupiao.baidu.com/stock/'
    output_file = 'D:/BaiduStockInfo.txt'
    slist=[]
    getStockList(slist, stock_list_url)
    getStockInfo(slist, stock_info_url, output_file)

main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值