一、目标
目标很简单,就是爬取陕西省各个城市的天气信息,保存在本地!
话不多说,先来张图看看最终的结果。
这就是我们最终希望得到的,这里简单说明一下,大部分天气网站的天气信息可能是图标,图片,或者动图,这些肯定是不能保存在txt文件中的,最终可能的结果如上图所示。在本文最后,会贴出来爬取动态图片的代码,供大家参考交流。
二、安装依赖
1. import urllib.request
urllib是python内置的http请求库,不需要安装直接就可以使用
2. from bs4 import BeautifulSoup
bs4是一个非常简单易用的解析工具,anaconda自带,也可以通过pip下载
3. import datetime
datetime是python自带的时间模块,主要是为了记录爬取的时间信息
三、元素选择简单介绍
- 我是测试001
- 我是测试002
如果你写过css,那你一定清楚,如果我们希望定位li标签下的‘我是测试001’和‘我是测试002’。
常用的方法是使用标签选择器,id选择器,类选择器等等,不同的选择器可以复合使用。
标签选择器:直接将标签名作为选择器。例如‘div’,即可选择所有div标签下的元素
id选择器:使用‘#’+标签的id名作为选择器,每个标签的id是唯一的不可重复。例如‘#testid’,即可选中id为‘testid’的标签
类选择器:使用‘.’+标签的class作为选择器,不同标签的class可能相同。例
如‘.testclass’,即可选择有calss为‘testclass’的标签
同时,也将不同的选择器组合起来使用,例如上述示例代码中,为了精准定位‘我是测试001’和‘我是测试002’,可以这样写:`#testid .testclass ul li`
它的意思是,id是testid标签下的类名为testclass标签下的ul标签下的li标签。
bs4可以为我们提供一样的语法来帮我们定位解析爬取下来的文档内容,获取我们想要的信息。这也是为什么bs4简单易用的原因。
除了上述的选择器定位元素之外,还有其他的方法诸如:xpath、正则等。
四、分析网页,定位信息
在开始写爬虫之前,我们先分析一下将要爬取的天气网站,看看我们希望得到哪些信息。
⚠爬虫爬取数据需要注意法律规范,严禁恶意攻击他人网站,或者盗用别人的数据非法盈利
框出来的部分就是我们想要的信息,接着定位我们希望得到的信息。
浏览器的控制台可以帮助我们快速定位元素,以谷歌浏览器为例:
按下图的步骤操作之后,再在页面上点击自己希望定位的元素。
接着按照上面提到的选择器,定位元素即可。
以西安为例:
首先,我们希望爬取的所有信息都在类名为forecast的div标签下的类名forecastBox的div标签下的dl标签中。
城市名在dt标签下的a标签中。(✨✨这里插一嘴,a标签是一个点击之后可以跳转至新页面的标签,新页面的url地址就是a标签上href指定的内容,即点击西安之后,我们就能跳转下面的网页。很显然这个页面是西安天气更加详细的详细信息,urllib可以帮助我们爬取a标签指定的页面的内容。所以我们可以顺便定位分析这个页面的内容,获取更加详细的天气信息。定位的方法大同小异,大家可以自己试试)
dd标签下的第一个a标签下有两个img标签,分别对应了白天的天气和夜间的天气,这就是开头提到的不能保存在txt文件中的图片,只能存下来图片的路径了(网站中有专门介绍天气图标的页面)
dd标签下的第二个a标签和第三个a标签下面的span标签则是今日的最高气温和最低气温
细心的伙伴可能会发现,存在很多个dl标签,这就是写法规范的网站,陕西省下面的其他城市都和西安是类似的,这其实也为我们提供了便利,使用bs4定位的时候,会直接把所有城市的数据都解析出来,存在一个列表里。
五、爬虫实现
引入依赖
import urllib.request
from bs4 import BeautifulSoup
import datetime
获取当前时间,写入文件
now_time = datetime.datetime.now()
time1_str = datetime.datetime.strftime(now_time,'%Y-%m-%d %H:%M:%S')
fl = open(r'陕西省天气信息.txt',"a+",encoding='utf-8')
fl.write("抓取时间:"+time1_str)
fl.write('\n')
fl.close()
主要是python的文件操作,这里小小偷个懒,大家自己search吧
爬取文档
url="http:/testt/test.shtml" #示例url,并不真实存在
response=urllib.request.urlopen(url)
d=response.read()
soup=BeautifulSoup(d,"lxml")
python内置的urllib下的request模块的urlopen使用GET方式对网站发起请求
urlopen返回的response对象是http.client.HTTPResponse类型,主要包含read()、readinfo()、getheader(name)、getheaders()、fileno()等方法。
使用BeautifulSoup对文档解析,第一个参数是要解析的文档内容,第二个参数声明解析的方式,一般lxml已经足够使用了。具体的信息网上有很多,这里继续偷懒
- 解析元素
ls_Url_Name = soup.select('.forecastBox dl dt a')
ls_WeatherInfo = soup.select('.forecastBox dl dd a img')
ls_MinTem = soup.select('.forecastBox dl dd a b')
ls_TopTem = soup.select('.forecastBox dl dd a span')
使用select可以按照上面介绍的选择器快速访问标签
ls_Url_Name是一个存放每个城市名a标签的列表
ls_WeatherInfo是存放每个城市白天气温和夜间气温img标签的列表
ls_MinTem是存放每个城市最低气温的列表
ls_TopTem是存放每个城市最高气温的列表
PS:最低气温和最高气温虽然解析了,但是并没有写入文件中,这里打印一下,让大家看看解析出来的列表长什么样子
遍历列表、组装信息
j=0
for i in range(0,len(ls_Url_Name)):
str1 = ""
str1 = str1 + ls_Url_Name[i].get_text()+"\n"
str1 = str1 + "白天天气信息:" + ls_WeatherInfo[j].attrs['src'] + " "
str1 = str1 + "夜晚天气信息:" + ls_WeatherInfo[j+1].attrs['src'] + "\n"
j+=2
这里就用最简单字符串拼接的方法来组装我们需要的信息。
有了上述标签列表,bs还提供了一些方法帮助我们获取标签中的信息
get_text()可以获取标签中的文本信息
PS:声明一个j变量,每次循环的时候j的步数应该是2,因为每个城市有白天和夜晚两个气温
获取a标签的href,进去详情页面
url = ls_Url_Name[i].attrs['href']
response=urllib.request.urlopen(url)
d=response.read()
soup=BeautifulSoup(d,"lxml")
str1 = str1 + "当前天气信息:" + soup.select('.c7d ul li .wea')[0].get_text() + "\n"
str1 = str1 + "当前气温:" + soup.select('.c7d ul li .tem')[0].get_text()
str1 = str1 + "当前风向:" + soup.select('.c7d ul li .win em span')[0].attrs['title'] + " " + "当前风速:" + soup.select('.c7d ul li .win i')[0].get_text() + '\n'
print(str1)
bs解析出的标签的attrs中包含了元素的各个属性,我们要得到的就是a标签的href属性
获得详情页面的url之后,和之前的操作方法相同,请求详情页面,解析元素,获得我们需要的信息,组装字符串,最后写进文件即可
附上遍历列表的完整代码
j=0
for i in range(0,len(ls_Url_Name)):
str1 = ""
str1 = str1 + ls_Url_Name[i].get_text()+"\n"
str1 = str1 + "白天天气信息:" + ls_WeatherInfo[j].attrs['src'] + " "
str1 = str1 + "夜晚天气信息:" + ls_WeatherInfo[j+1].attrs['src'] + "\n"
j+=2
url = ls_Url_Name[i].attrs['href']
response=urllib.request.urlopen(url)
d=response.read()
soup=BeautifulSoup(d,"lxml")
str1 = str1 + "当前天气信息:" + soup.select('.c7d ul li .wea')[0].get_text() + "\n"
str1 = str1 + "当前气温:" + soup.select('.c7d ul li .tem')[0].get_text()
str1 = str1 + "当前风向:" + soup.select('.c7d ul li .win em span')[0].attrs['title'] + " " + "当前风速:" + soup.select('.c7d ul li .win i')[0].get_text() + '\n'
print(str1)
fl = open(r'陕西省天气信息.txt',"a+",encoding='utf-8')
fl.write(str1)
fl.write('\n')
fl.close()
完
附:爬取天气图标
import os
ls = soup.select('.forecastBox dl dd a img')
j=1 #爬取天气图标测试
for i in ls:
str1 = i.attrs['src']
str1 = page1 + str1
if os.path.exists("D:/imags") == False:
os.mkdir("D:/imags")
bytes = urllib.request.urlopen(str1)
str3 = "D:/imags/test"+str(j)+'.gif'
f = open(str3,'wb')
f.write(bytes.read())
f.flush()
f.close()
j+=1
为了防止一些坏人恶意高频率访问人家的网站,这里就不提供网站的地址了,大家可以自己找一些网站自己操作。
在未告知对方的前提下,获得的数据切记不得私自用于盈利,不能影响别人呦。
最近疫情非常严重,尤其是上海,希望我们的祖国能够尽快战胜疫情,大家一定做好防护,祝大家身体健康