实验十三 网页爬虫
第1关:爬取网页的表格信息
湖南省统计局的湖南省第七次全国人口普查公报(第六号)网址如下: https://tjj.hunan.gov.cn/hntj/tjfx/tjgb/pcgbv/202105/t20210519_19079329.html
表格的内容存储在 <table></table>
标签中。
爬取该页面的表格标签下的内容,存储在字符串 bg
中。
如何爬取网页数据
网络爬虫应用一般分为两个步骤:
(1)通过网络连接获取网页内容:
requests
(2)对获得的网页内容进行处理:
beautifulsoup4
在调用 requests.get(url)
函数后,返回的网页内容会保存为一个 response
对象,该对象的text
属性会返回所有的网页文本。
使用 BeautifulSoup()
可创建一个 BeautifulSoup
对象。BeautifulSoup
的 find(<name>)
方法, name
为标签名。可在 HTML
文档中按照标签名返回标签内容 soup.find('table')
可返回 table
标签下的所有内容。
爬取网页 https://tjj.hunan.gov.cn/hntj/tjfx/tjgb/pcgbv/202105/t20210519_19079329.html
, 将表格标签下的内容存储在字符串 bg
中。
import requests
from bs4 import BeautifulSoup
#代码开始
url = "https://tjj.hunan.gov.cn/hntj/tjfx/tjgb/pcgbv/202105/t20210519_19079329.html"
html = requests.get(url)
html.encoding = 'utf-8'
soup = BeautifulSoup(html.text,"html.parser")
bg = soup.find('table')
#代码结束
print(bg)
第2关:爬取表格中指定单元格的信息
本关任务:根据上个步骤中爬取的表格标签,将表格中从第四行的单元格的文本显示出来。
行标签和单元格标签
表格中每行的数据信息被封装在一个 <tr></tr>
之间的结构中。每列内容采用 <td></td>
表示。
因此,如果要获得其中的数据,需要首先找到 <tr></tr>
标签,并遍历其中每个 <td></td>
标签,获取其值。例如,表格的第四行对应的 html
代码如下:
find_all函数
通过 BeautifulSoup
的 find_all(name)
方法,可以找到多个标签,将多个标签的内容返回为一个列表 lb=bg.find_all("tr")
。找到表格的所有 tr
标签,存入列表 lb
,若需要找每行下的所有 td
标签,则需要对 lb
循环,对每个元素执行 find_all("td")
。
获取标签文本
在用 find()
方法找到特定的标签后,想获取里面的文本,可以用 .text
属性或者 .string
属性。
- 如果该标签下有多层次的子标签,则必须使用
text
属性; - 对于该网页的
td
标签,如上图所示,需要用text
才能返回文本。并且需要用strip
去掉换行符; - 如果使用最内层的
span
标签,则可以使用string
属性。
对于上述获得的表格标签的内容,爬取从第 4 行开始的文本,显示每行的地区名称、总人口、城镇人口、乡村人口和城镇化率。各项之间用空格隔开,包括最后一列后面也有空格每个地区换一行
import requests
from bs4 import BeautifulSoup
url = "https://tjj.hunan.gov.cn/hntj/tjfx/tjgb/pcgbv/202105/t20210519_19079329.html"
r=requests.get(url)
r.encoding = 'utf-8'
soup=BeautifulSoup(r.text,"html.parser")
bg=soup.find('table')
#代码开始
import re
tr1 = bg.find_all("tr")
lb = []
lb1 = []
for li in tr1:
lb.append(li.find_all("td"))
lb = lb[3:]
for k,i in enumerate(lb):
lb1.append([])
for j in i:
res = re.match(r'.*宋体\">(.*?)</span>',str(j),re.S)
lb1[k].append(res.group(1))
for i in lb1:
for j in i:
print(j,end=" ")
print()
#代码结束
第3关:将单元格的信息保存到列表并排序
本关任务:根据上个步骤中爬取的表格内容,将城市名称和人口数存放在列表 lb
中,按人口数降序排列后输出。
提示:存入列表时,只需要存入两列,需将人口数转换为数值型才能按照数值的降序排列,可以用 isnumeric
方法判断是否数字字符。
import requests
from bs4 import BeautifulSoup
url = "https://tjj.hunan.gov.cn/hntj/tjfx/tjgb/pcgbv/202105/t20210519_19079329.html"
r=requests.get(url)
r.encoding = 'utf-8'
soup=BeautifulSoup(r.text,"html.parser")
bg=soup.find('table')
lb=[]
#代码开始
import re
tr1 = bg.find_all("tr")
lb1 = []
for li in tr1:
lb1.append(li.find_all("td"))
lb1 = lb1[3:]
for k,i in enumerate(lb1):
lb.append([])
for j in i:
res = re.match(r'.*宋体\">(.*?)</span>',str(j),re.S)
if res.group(1).isnumeric():
lb[k].append(eval(res.group(1)))
else:
lb[k].append(res.group(1))
lb.sort(key=lambda x:x[1],reverse=True)
# #代码结束
for lbxx in lb:
print(lbxx[0],lbxx[1])
第4关:爬取 div 标签的信息
编写一个爬取湖南大学讲座信息网页的程序。
湖南大学讲座信息的网址为 https://www.hnu.edu.cn/xysh/xshd.htm
。
网页如下:
注意:随着时间不同,网页的内容会变化
其对应的代码如下:
编写程序,爬取该页第一个讲座的时间、标题、主讲人和地点信息,存储在字符串 jzsj
、jzbt
、jzdd
中,如下所示:
分析该网页,可以观察到:
-
每个讲座信息放在
class
为xinwen-wen
的div
标签下; -
讲座时间包含在
class
为xinwen-sj-top
的div
标签下; -
讲座标题包含在
class
为xinwen-wen-bt
的div
标签下; -
讲座主讲人地点包含在
class
为xinwen-sj-top
的div
标签下。
你需要掌握:如何爬取指定属性的 div
标签下的信息。
通过 BeautifulSoup
的 find()
方法,可以按照条件找到标签,返回标签的内容。
find(name, attrs)
name
: 按照T
标签名字检索,名字用字符串形式表示,例如div
,li
。attrs
: 按照标签属性值检索,需要列出属性名称和值。
xw=soup.find("div", class_="xinwen-wen")
可以返回 xinwen-wen
标签下的内容。
在该内容下继续按照 class
为 xinwen-wen-top
的条件使用 find
,可以找到讲座时间的标签。
jzsjbq=xw.find("div", class_="xinwen-wen-top")
该标签的 text
属性即为讲座时间。
注意:该文本中有空格和换行符,需要使用
strip
去掉。
import requests
from bs4 import BeautifulSoup
url = 'https://www.hnu.edu.cn/xysh/xshd.htm'
r = requests.get(url)
r.encoding = 'utf-8'
#代码开始
soup = BeautifulSoup(r.text, "html.parser")
lb = soup.find_all("div", class_="xinwen-wen")
for i in lb:
jzsj = i.find("div", class_= "xinwen-sj-top").text.strip()
jzbt = i.find("div", class_= "xinwen-wen-bt").text.strip()
jzdd = i.find("div", class_= "xinwen-wen-zy").text.strip()
#代码结束
f1=open("jzxx.txt","w")
f1.write(jzsj+"\n")
f1.write(jzbt+"\n")
f1.write(jzdd+"\n")
f1.close()
第5关:爬取单页多个div标签的信息
改进上一关的代码。爬取湖南大学讲座网页的多个讲座信息,存储在二维列表 jzxx
中。
湖南大学讲座信息的网址为 https://www.hnu.edu.cn/xysh/xshd.htm
。
相关知识
1. find_all 函数
通过 BeautifulSoup
的 find_all(name,attr)
方法,可以找到符合条件的多个标签,将多个标签的内容返回为一个列表。
lb=bg.find_all("div",class="xinwen-wen")
找到网页的所有 class
属性为 xinwen-wen
的 div
标签,存入列表 lb
。
2. 列表的操作
对于得到的多个标签的列表,使用 for
循环,可以依次访问每个标签,使用 find
函数找出其时间、标题和地点的文本,加入到列表,再加入二维列表 jzxx
中。
爬取湖南大学讲座网页的多个讲座信息,存储在二维列表 jzxx
中。
import requests
from bs4 import BeautifulSoup
url = 'https://www.hnu.edu.cn/xysh/xshd.htm'
r = requests.get(url)
r.encoding = 'utf-8'
jzxx=[]
#代码开始
soup = BeautifulSoup(r.text, "html.parser")
lb = soup.find_all("div", class_="xinwen-wen")
for i in lb:
jzsj = i.find("div", class_= "xinwen-sj-top").text.strip()
jzbt = i.find("div", class_= "xinwen-wen-bt").text.strip()
jzdd = i.find("div", class_= "xinwen-wen-zy").text.strip()
jzxx.append([jzsj,jzbt,jzdd])
#代码结束
f1=open("jzxx2.txt","w")
for xx in jzxx:
f1.write(",".join(xx)+"\n")
f1.close()
第6关:爬取多个网页的多个div标签的信息
修改上关的程序,爬取从第 80 页到 85 页中的讲座信息,存放在 jz.txt
文件中每行显示一个讲座信息,讲座时间、讲座标题和主讲人地点用逗号分隔。
湖南大学讲座信息的第 80 页的网址为 https://www.hnu.edu.cn/xysh/xshd/80.htm
。
获取爬取多个网页
为了爬取多个网页,你需要通过循环产生多个不同 url
地址,再调用 requests
库的 get
方法,获得多个网页的 url
。
如何将信息写入文件
首先以 w
方式打开文件,再通过文件对象的 write
方法将字符串写入文件。
import requests
from bs4 import BeautifulSoup
f1=open("jz.txt","w",encoding="utf8")
#代码开始
for i in range(80,86,1):
respose = requests.get(f'https://www.hnu.edu.cn/xysh/xshd/{i}.htm')
respose.encoding = 'utf-8'
content = respose.text
soup = BeautifulSoup(content,'html.parser')
all_div = soup.findAll('div',class_='xinwen-wen')
for div in all_div:
jzsj = div.find('div',class_= 'xinwen-sj-top').string.strip()
jzbt = div.find('div',attrs={'class','xinwen-wen-bt'}).string.strip()
jzdd = div.find('div',attrs={'class','xinwen-wen-zy'}).text.strip()
f1.write(jzsj+','+jzbt+','+jzdd+'\n')
#代码结束
f1.close()