爬虫能干什么呢?一句话概括,正常通过浏览器可以获取的数据,爬虫都可以获取。这句话可以说是包罗万象。一是说明了爬虫的本质是一个服务端,实现的功能类似于浏览器;二是说明了爬虫的界限,如果不能正常访问到的数据就不能通过爬虫获取;三是爬虫的最高境界,只要是浏览器能正常访问的都可以用爬虫获取。
爬虫:我们需要干的事情其实就两件事情:找到我们需要的网页,然后把他们一个一个处理一遍。一,怎么找到我们需要的网页的那个入口?二,怎么处理我们需要处理的网页?
爬虫的核心模块有三个:请求、解析、储存。
- 请求
我们先使用requests包。这是一个第三方模块,对HTTP协议进行了高度封装,非常好用。HTTP协议:简单地说就是一个请求过程。服务器响应并返回相应数据,我们要实现的目的是把网页请求(或者说下载)下来。
安装requests
pip install requests
导入requests
import requests
调用requests的get函数,把网页请求下来
r = requests.get('www.baidu.com')
输出请求下来的网页格式
print(r.text)
requests的一些属性
>>> import requests
>>> r = requests.get("http://www.baidu.com")
>>> r.status_code
200
>>> r.endcoding = 'utf-8'
>>> r.text
requests异常问题
一些小实例
# 实例1:
import requests
url = "https://item.jd.com/1350837.html"
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[:1000])
except:
print("爬取失败")
#实例2 搜索引擎关键字搜索
import requests
r = requests.get(url='http://www.itwhy.org') # 最基本的GET请求
print(r.status_code) # 获取返回状态
r = requests.get(url='http://dict.baidu.com/s', params={'wd':'python'}) #带参数的GET请求
#params为url中的额外参数,字典或字节流格式
print(r.url)
print(r.text) #打印解码后的返回数据
#ip地址查询
#www.ip138.com
import requests
url = "http://m.ip138.com/ip.asp?ip="
try:
r = requests.get(url+'210.40.17.226')
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[-500:])
except:
print("爬取失败")
#用来页面验证、人机交互
- 解析
requests包可以使用http协议获取相应的网页文件,但是往往请求下来的是整个页面的代码,这样的信息太多了,从这一大坨代码里面找信息太麻烦了。我们需要另一个库来解析文件:BeautifulSoup4(bs4)
bs4安装:
pip install beautifulsoup4
bs4是一个非常好的解析网页的库。这次的解析先给大家看bs4里面最常用的几个BeautifulSoup对象的方。我们使用的这几个方法,主要是通过HTML的标签和标签里面的参数来定位,然后用特定方法提取数据。
beautifulsoup的简单使用:
form bs4 import BeautifulSoup
......
soup = BeautifulSoup(html,'html.parser') #html.parser是解析器
#还有 lxml的html lxml的xml html5lib 解析器
#<p>data</P>可以替换成其他的html属性
测试链接:python123.io/ws/demo.htm…
测试这个网页:
import requests
r = requests.get('https://python123.io/ws/demo.html')
print(r.text)
返回信息:
<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 href="http://www.icourse163.org/course/BIT-268001" class="py1" id="link1">Basic Python</a> and <a href="http://www.icourse163.org/course/BIT-1001870001" class="py2" id="link2">Advanced Python</a>.</p>
</body>
</html>
开始解析:
import requests
from bs4 import BeautifulSoup
r = requests.get('https://python123.io/ws/demo.html')
demo = r.text
soup = BeautifulSoup(demo,"html.parser")
#soup2 = BeautifulSoup(open("D://demo.html"),"html.parser")
print(soup.prettify())
理解:
#html文件的大概框架
<html>
<body>
<div class="abc"></div>
<p class="bcd"></p> #标签格式<p></p> 此处标签name就是p,class="bcd"是属性域,键值对构成
</body>
b</html>
#BeautifulSoup是解析、遍历、维护、“标签书”的功能库
BeautifulSoup类的基本元素
1.Tag:标签。最基本的信息组织单元,<>、</>开头和结尾
2.Name:标签的名字,格式:< tag>.name
3.Attributes:标签的属性,字典形式组织,格式< tag>.attrs
4.NavigableString:标签内的非属性字符串,格式< tag>.string
5.Comment:标签内字符串的注释部分,一种特殊的Comment类型
解析1:
import requests
from bs4 import BeautifulSoup
r = requests.get('https://python123.io/ws/demo.html')
demo = r.text
soup = BeautifulSoup(demo,"html.parser")
print(soup.prettify())
print("-------------------------------")
print(soup.title)
print("-------------------------------")
print(soup.a)
print("-------------------------------")
print(soup.a.name)
print("-------------------------------")
print(soup.a.parent.name)
print("-------------------------------")
print(soup.a.parent.parent.name)
解析2:
import requests
from bs4 import BeautifulSoup
r = requests.get('https://python123.io/ws/demo.html')
demo = r.text
soup = BeautifulSoup(demo,"html.parser")
tag = soup.a
print("-------------------------------")
print(tag.attrs)
print("-------------------------------")
print(tag.attrs['class'])
print("-------------------------------")
print(tag.string)
print("-------------------------------")
print(soup.p.string)
解析3:
1.下行遍历:
.contents:子节点的列表,将< tag>所有的儿子节点存入列表
.childen:子节点的迭代类型,与.contents类似,用于循环遍历儿子节点
.desendants:子孙节点的迭代类型,包括所有的子孙节点,用于循环遍历
import requests
from bs4 import BeautifulSoup
r = requests.get('https://python123.io/ws/demo.html')
demo = r.text
soup = BeautifulSoup(demo,"html.parser")
print("-------------------------------")
print(soup.head)
print("-------------------------------")
print(soup.head.contents)
print("-------------------------------")
print(soup.body.contents)
print("-------------------------------")
print(len(soup.body.contents)) #获得body儿子节点的数量(个数)
print("-------------------------------")
print(soup.body.contents[1]) #因为存放的方式为列表,可以用列表下表的方式获取
print("-------------------------------")
for child in soup.body.children: #遍历儿子节点
print(child)
print("--")
2.上行遍历:
.parent:节点的父亲标签
.parents:节点先辈标签的迭代类型,用于循环遍历先辈节点
import requests
from bs4 import BeautifulSoup
r = requests.get('https://python123.io/ws/demo.html')
demo = r.text
soup = BeautifulSoup(demo,"html.parser")
print("-------------------------------")
print(soup.head)
print("-------------------------------")
print(soup.head.parent)
print("-------------------------------")
for parent in soup.a.parents: #上行遍历
if parent is None:
print(parent)
else:
print(parent.name)
3.平行遍历:
.next_sibling:返回下一个平行节点
.previous_sibling:返回上一个平行节点
.next_siblings:返回后续的所有平行节点
.previous_siblings:返回前序的所有平行节点
实战小项目:
#爬取中国大学排名
import requests
from bs4 import BeautifulSoup
import bs4
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 fillUnivList(ulist, html):
soup = BeautifulSoup(html, "html.parser")
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[3].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 = 'http://www.zuihaodaxue.com/zuihaodaxuepaiming2019.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 100) # 100 univs
main()
#一周天气
import csv
import urllib.request
from bs4 import BeautifulSoup
url = "http://www.weather.com.cn/weather/101270101.shtml"
header = ("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36") # 设置头部信息
opener = urllib.request.build_opener() # 修改头部信息
opener.addheaders = [header] #修改头部信息
request = urllib.request.Request(url) # 制作请求
response = urllib.request.urlopen(request) # 得到请求的应答包
html = response.read() #将应答包里面的内容读取出来
html = html.decode('utf-8') # 使用utf-8进行编码,不重新编码就会成乱码
final = [] #初始化一个空的list,我们为将最终的的数据保存到list
bs = BeautifulSoup(html,"html.parser") # 创建BeautifulSoup对象
body = bs.body # 获取body部分
data = body.find('div',{'id':'7d'}) # 找到id为7d的div
ul = data.find('ul') # 获取ul部分
li = ul.find_all('li') # 获取所有的li
# print (li)
i = 0
for day in li: # 对每个li标签中的内容进行遍历
if i < 7:
temp = []
date = day.find('h1').string # 找到日期
# print (date)
temp.append(date) # 添加到temp中
# print (temp)
inf = day.find_all('p') # 找到li中的所有p标签
# print(inf)
# print (inf[0])
temp.append(inf[0].string) # 第一个p标签中的内容(天气状况)加到temp中
if inf[1].find('span') is None:
temperature_highest = None # 天气预报可能没有当天的最高气温(到了傍晚,就是这样),需要加个判断语句,来输出最低气温
else:
temperature_highest = inf[1].find('span').string # 找到最高温度
temperature_highest = temperature_highest.replace('℃', '') # 到了晚上网站会变,最高温度后面也有个℃
temperature_lowest = inf[1].find('i').string #找到最低温度
temperature_lowest = temperature_lowest.replace('℃', '') # # 最低温度后面有个℃,去掉这个符号
temp.append(temperature_highest)
temp.append(temperature_lowest)
final.append(temp)
i = i +1
# print(final)
with open('weather.csv', 'a', errors='ignore', newline='') as f:
f_csv = csv.writer(f)
f_csv.writerows(final)