爬虫学习
1、 第一只爬虫:
import requests
r = requests.get("http://www.baidu.com")
# HTTP请求的返回状态,200表示连接成功,404表示失败
print(r.status_code)
# # r的类型,属于Response
# print(type(r))
#
# # 请求的头部部分
# print(r.headers)
# HTTP响应内容的字符串形式,即,url对应的页面内容
# 基本会出现乱码
print(r.text)
# 从HTTP header中猜测的响应内容的编码方式
print(r.encoding)
# 从内容中分析出的响应内容编码方式(备选编码方式)
print(r.apparent_encoding)
# 解决乱码问题
r.encoding = "utf-8"
print(r.text)
# HTTP响应内容的二进制形式
print(r.content)
爬虫基本框架:
import requests
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status() # 如果状态不是200,引发HTTPEroor异常
r.encoding = r.apparent_encoding
return r.text
except:
return "产生异常"
if __name__ == "__main__": # TODO 有点不懂
url = "http://www.baidu.com"
print(getHTMLText(url))
robots协议:
查看方式:http://*****.com/robots.txt
爬取京东华为手机信息:
1、简洁版
import requests
r = requests.get("https://item.jd.com/4203985.html")
# 检查访问是否正常
print(r.status_code)
# 由头部检查网页编码方式
print(r.encoding)
# 提取text里边从0到1000的字符信息
print(r.text[:1000])
2、 安全版
import requests
url = "https://item.jd.com/4203985.html"
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[:1000])
except:
print("爬取失败!")
爬取亚马逊:(模拟浏览器,向网站发起请求)
说明:针对不对爬虫开放的网站进行爬取
1、 简洁版:
import requests
"""解决办法,修改User-Agent为一个浏览器字段
Mozilla/5.0是一个标准浏览器字段(被多种浏览器采用)
"""
kv = {"user-agent": "Mozilla/5.0"}
url = "https://www.amazon.cn/dp/B01M8L5Z3Y/ref=sr_1_1?s=books&ie=UTF8"\
"&qid=1519982182&sr=1-1&keywords=%E6%9E%81%E7%AE%80"
# headers 方法修改。。。请求信息
r = requests.get(url, headers=kv)
print(r.encoding) # url头部为utf-8格式
print(r.status_code)
# 'user-agent': 'Mozilla/5.0' 表明修改成功
print(r.request.headers)
print(r.text[:1000])
2、 安全版
import requests
url = "https://www.amazon.cn/dp/B01M8L5Z3Y/ref=sr_1_1?s=books&ie=UTF8"\
"&qid=1519982182&sr=1-1&keywords=%E6%9E%81%E7%AE%80"
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])
except:
print("爬取失败!")
百度360搜索关键字提交:
说明:使用360搜索时,把wd修改为q就行了,其他都一样
1、 简洁版
import requests
kv = {"wd": "python"}
r = requests.get("http://baidu.com/s", params=kv)
# 访问状态
print(r.status_code)
# 发给百度的url实际上是什么
print(r.request.url)
2、 安全版
import requests
keyword = "python"
try:
kv = {"wd":keyword}
r = requests.get("http://baidu.com/s", params=kv)
print(r.request.url)
r.raise_for_status()
# 显示爬取的文本长度
print(len(r.text))
except:
print("爬取失败!")
爬取国家地理图片:
1、 简洁版
import requests
path = "D:/abc.jpg"
url = "http://img0.dili360.com/rw9/ga/M00/02/AB/wKgBzFQ26i2AWujSAA_-xvEYLbU441.jpg"
r = requests.get(url)
print(r.status_code)
# print(r.text)
# 打开一个文件,并把它定义为一个文件标志符f
with open(path, "wb") as f:
# r.content表示返回内容的二进制形式,再使用write把他写出了
f.write(r.content)
f.close()
2、 安全版
import requests
import os # TODO 不会
url = "http://img0.dili360.com/rw9/ga/M00/48/4E/wKgBzFllve2AO9VBAEzNdvr41Hs146.tub.jpg"
# 定义一个根目录
root = "D://pics//"
# 定义本地路径的文件名称,而且与网络文件名最后一部分相同
path = root +url.split("/")[-1] # TODO 不会
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地址归属地自动查询:
1、 简洁版
import requests
kv = {"user-agent": "Mozilla/5.0"}
url = "http://m.ip138.com/ip.asp?ip="
r = requests.get(url + "202.204.80.112")
r = requests.get(url, headers=kv)
print(r.status_code)
print(r.request.headers)
r.encoding = r.apparent_encoding
print(r.text[-500:])
2、 安全版
import requests
url = "http://m.ip138.com/ip.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("爬取失败!")
beautifulsoup库安装:
import requests
r = requests.get("https://python123.io/ws/demo.html")
print(r.text)
demo = r.text
# 导入beautiful库
from bs4 import BeautifulSoup
# 对demo进行解析(使用html.parse解释器进行解析)
soup = BeautifulSoup(demo, "html.parser")
print(soup.prettify())
信息提取:
说明:提取网站源码中的网址链接
# 提取HTML中所有的url链接
import requests
from bs4 import BeautifulSoup
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
for link in soup.find_all("a"):
print(link.get("href"))
基于bs4库的HTML内容查找方法:
import requests
from bs4 import BeautifulSoup
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
"""BeautifulSoup库提供了一个方法,如下(查找信息)
<>.find_all(name, attrs, recursive, string, **kwargs)
返回一个列表类型,储存查找的结果
name:对标签名称的检索字符串
attrs:对标签属性值的检索字符串,可标注属性检索
recursive:是否对某一个标签子孙所有节点进行搜索,默认是True(是一个布尔类型的值)
string:对<>..</>中的字符串区域的检索字符串
"""
""" name方法 """
# # 查找a 标签内容
# print(soup.find_all("a"))
# # 查找a b 两个标签内容
# print(soup.find_all(["a", "b"]))
#
# # 查看有多少个标签(tag)
# for tag in soup.find_all(True):
# print(tag.name)
#
# print("")
# """若只显示以b开头的标签(tag),
# 这里需要正则表达式库
# """
# # 导入正则表达式库
# import re
# for tag in soup.find_all(re.compile("b")):
# print(tag.name)
""" attrs 方法 """
# # 输出一个带有course属性值的标签
# print(soup.find_all("p", "course"))
# print("")
#
# # 查找某个属性值=**,作为查找依据(查找必须十分精确,不然返回空列表)
# print(soup.find_all(id="link1"))
# print("")
#
# """针对根据属性查找必须十分精确,解决措施(导入正则表达式)
# 进行比较模糊的查找
# """
# import re
# print(soup.find_all(id=re.compile("link"))) # 查找内容明显比上面多
""" recursive方法 """
# print(soup.find_all("a"))
# # 检查a 标签下的子节点没有内容,返回空列表[]
# print(soup.find_all("a", recursive=False))
""" string """
# print(soup) # 查看一下soup完整信息
# print("")
# # 同样查找依据必须十分精确(输入的字符串必须精确)
# print(soup.find_all(string="Basic Python"))
# print("")
# # 同样如果引入正则表达式,就可以进行模糊检索soup里的内容
# import re
# print(soup.find_all(string=re.compile("python")))
中国大学排名定向爬虫:
程序结构设计:
步骤一: 从网络上获取大学排名网页内容
步骤二:提取网页内容中的有用信息并把他放到合适的数据结构中
步骤三:利用数据结构展示并输出结果
import requests
from bs4 import BeautifulSoup
import bs4
"""获取url信息,输出url内容"""
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""
"""将这一个页面放到ulist中"""
def fillUnivList(ulist, html):
# 解析HTML
soup =BeautifulSoup(html, "html.parser")
# 解析html中tbody所在位置,在tbody标签中找到每一所大学对应的tr标签
for tr in soup.find("tbody").children:
# 在tr标签中找到其中td标签的信息,并把需要的标签加到列表中
# isinstance是bs4库中方法,筛选tr中有标签的信息(排除没有标签的信息)
if isinstance(tr, bs4.element.Tag):
tds = tr("td")
ulist.append([tds[0].string, tds[1].string, tds[2].string])
"""将ulist信息打印出来"""
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 = "http://zuihaodaxue.cn/shengyuanzhiliangpaiming2018.html"
html =getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20) # 获取20所学校排名
main()
Beautiful Soup库:
bs类基本元素:
Tag:标签,基本信息组织单元,分别用<>和</> 标明开头和结尾
Name:标签的名字,<>…</p>的名字是’p’ ,格式:<tag>.name
Attributes:标签属性,字典形式组织,格式<tag>.attrs
NavigableString: 标签内非属性字符串,<>…</>中字符串,格式:<tag>.string
Comment:标签内部字符串的注释部分,一种特殊的Comment类型
from bs4 import BeautifulSoup
import requests
r = requests.get("https://python123.io/ws/demo.html")
print(r.text)
print("")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
print(soup.title) # 打印title标签
print("")
# # a 标签
# tag = soup.a
# print(tag)
# # 获取a 标签名字、a父亲的名字(p)、a爷爷标签的名字(body)
# print(soup.a.name)
# print(soup.a.parent.name)
# print(soup.a.parent.parent.name)
# 标签中非属性字符串,NavigableString: 标签内非属性字符串,<>…</>中字符串,格式:<tag>.string
# comment 注释
newsoup = BeautifulSoup()
基于bs4库的HTML内容遍历方法:
from bs4 import BeautifulSoup
import requests
r = requests.get("https://python123.io/ws/demo.html")
# print(r.text)
print("")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
"""标签树的下行遍历:.contents指将标签所有子节点存入列表
.children指用于循环遍历儿子节点
.descendants 子孙节点的迭代类型,包含所有子孙节点,用于遍历
"""
# # .contents用法
#
# # head标签、以及他的儿子节点
# print(soup.head)
# print("")
# print(soup.head.contents) # 儿子节点
# # 查看body 标签儿子的信息
# print(soup.body.contents)
# print(len(soup.body.contents)) # 获取body 标签儿子的数量(5个)
# print(soup.body.contents[1]) # 获取body 标签儿子节点的第二个
# # .children用法
# for child in soup.body.children:
# print(child)
# # .descendants用法
# for child in soup.body.descendants:
# print(child)
"""标签树的上行遍历
.parent 节点的父亲标签
.parents 节点的先辈(包含父亲及其以上)标签的迭代类型,用于循环遍历先辈节点
"""
# # parent用法
# print(soup.title.parent) # title的父亲是head标签
# print("")
# print(soup.html.parent) #html 标签是最高级的标签类型,他的父亲就是自己
# print("")
# print(soup.parent) # soup本身就是一种特殊标签,他的父亲是空的
# # 标签树的上行遍历
# for parent in soup.a.parents:
# print(parent)
# else:
# print(parent.name)
"""标签树的平行遍历(只能发生在同一个父亲节点下的各节点间)
.next_sibling:返回按照HTML文本顺序的下一个平行节点标签
.previous_sibling:返回。。。上一个。。
.next_siblings:迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
.previous_siblings:迭代类型,。。。前续。。。
"""
# print(soup.a.next_sibling) # 标签可以是字符串
# print(soup.a.next_sibling.next_sibling) # a的下下个标签
# print(soup.a.previous_sibling) # a的上一个标签
# print(soup.a.previous_sibling.previous_sibling) # a的上上一个标签
# # 标签树的遍历
# for sibling in soup.a.next_siblings: #遍历后续节点
# print(sibling)
# for sibling in soup.a.previous_siblings: # 遍历前续节点
# print(sibling)
基于bs4库的HTML格式化:
from bs4 import BeautifulSoup
import requests
r = requests.get("https://python123.io/ws/demo.html")
# print(r.text)
print("")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
# soup.prettify() 用于给标签增加换行符,使输出内容更清晰(即格式化)
print(soup.prettify())
print("")
print(soup.a.prettify())
HTML:
HTML是www(World Wide Web)的信息组织方式
正则表达式:(regular expression .re)
变化最大的是年龄说明:正则表达式是用来简洁表达一组字符串的表达式
不把劳动作为第一生产力优势:简洁,可以简单地表达很大一个字符串的特征
re库基本使用:
"""
re库的函数用法:一次性使用
解释:pattern:正则表达式的字符串或原生字符串表示
string:待匹配字符串
flags:正则表达式使用时的控制标记
maxsplit:最大分割数,剩余部分作为最后一个元素输出
repl:替换匹配字符串的字符串
count:匹配的最大次数
re.search() 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
格式:re.search(pattern,string, flags=0)
re.match() 在一个字符串的开始位置起匹配正则表达式,返回match对象
格式:re.match(pattern,string, flags=0)
re.findall() 搜索字符串,以列表类型返回全部能匹配的子串
格式:re.findall(pattern,string, flags=0)
re.split() 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
格式:re.findall(pattern,string, maxsplit=0, flags=0)
re.finditer() 搜索字符串,返回匹配结果的迭代类型,每个迭代元素是match对象
re.finditer(pattern, string, flags=0)
re.sub() 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串
re.finditer(pattern, repl, string, count=0, flags=0)
"""
# # search函数
# import re
# match = re.search(r"[1-9]\d{5}", "BLT 100081")
# if match:
# print(match.group(0))
# # match函数
# import re
# match = re.match(r"[1-9]\d{5}", "BLT 100081")
# if match:
# # 匹配结果是空,无法输出结果
# print(match.group(0))
# print("")
# match = re.match(r"[1-9]\d{5}", "100081 BLT")
# if match:
# # 正常输出
# print(match.group(0))
# # findall函数
# import re
# ls = re.findall(r"[1-9]\d{5}", "BLT100081 TSU100084")
# # 返回一个列表
# print(ls)
# # split函数
# import re
# # 输出不匹配的字符串部分
# print(re.split(r"[1-9]\d{5}", "BLT100081 TSU100084"))
# # 只匹配第一个
# print(re.split(r"[1-9]\d{5}", "BLT100081 TSU100084",maxsplit=1))
# # finditer函数
# import re
# for m in re.finditer(r"[1-9]\d{5}", "BLT100081TSU100084"):
# if m:
# print(m.group(0))
# sub函数
import re
print(re.sub(r"[1-9]\d{5}", ":zipcode", "BLT100081 TSU100084"))
"""
re库的面向对象用法(先编译):多次使用,方法 regex = re.compile(pattern, flags=0)
regex(正则表达式)
pattern表示正则表达式的字符串或原生字符串,flags表示正则表达式使用时的控制标记
re库的等价用法:(方法同上)
regex.search():
regex.match():
regex.findall():
regex.split():
regex.finditer():
regex.sub():
"""
淘宝商品价格爬取:
import re
import requests
# 获得页面
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status() # 如果状态不是200,引发HTTPEroor异常
r.encoding =r.apparent_encoding
return r.text
except:
return ""
# 解析页面,获取商品名称、价格
def parsePage(ilt, html):
try:
plt = re.findall(r'\"view_price\"\:\"[\d\.]*\"', html) # TODO 为什么把高亮的斜杠 \ 去掉,程序还可以运行
tlt = re.findall(r'\"raw_title\"\:\".*?\"', html)
for i in range(len(plt)):
# eval函数可以将获取的字符串的双引号或单引号去掉
# spilt函数使用:分割字符串,获得键值对的后半部分
price = eval(plt[i].split(':')[1])
title = eval(tlt[i].split(':')[1])
ilt.append([price, title])
except:
print("")
# 将商品信息输出在屏幕上
def printGoodList(ilt):
# tplt 是打印模板
tplt = "{:4}\t{:8}\t{:16}"
# 打印表头
print(tplt.format("序号", "价格", "商品名称"))
count = 0
for g in ilt:
count = count + 1
print(tplt.format(count, g[0], g[1]))
# 定义主函数,记录程序运行整个过程
def main():
goods = "墨水"
# 爬取第一页和第二页,所以深度设为2
depth = 2
start_url = "http://s.taobao.com/search?q="+ goods
# 对输出变量定义一个变量
infoList = []
# 遍历页面信息,单独访问并处理每个页面
for i in range(depth):
# 使用try 对过程中发生的错误进行异常判断
try:
url = start_url + "&s="+ str(44*i)
html = getHTMLText(url)
parsePage(infoList, html)
except:
continue
printGoodList(infoList)
main()