前言
《项目实战 | python爬虫概述及实践(一)》中介绍了网络爬虫的定义、分类和基本流程。
这篇文章是介绍python爬虫的第二篇文章,主要关注如何从服务器响应的HTML文档中解析提取想要的信息,内容安排如下:
二、BeautifulSoup
BeautifulSoup是Python的一个库,主要功能是从网页中抓取需要的数据。
1.安装
首先我们需要安装BeautifulSoup库,可以在cmd下使用pip安装
pip install beautifulSoup4
2.使用
二话不说,先来一段简单的HTML文档
创建BeautifulSoup实例
from bs4 import BeautifulSoup
soup=BeautifulSoup(html,'html.parser')
#参数1:要匹配的内容
#参数2:采用的规则
find方法
语法:
Find(name,attrs,recursive,text,**wargs)
比如,我们要查找上述HTML文档中第一个<li>标签的内容
from bs4 import BeautifulSoup
soup=BeautifulSoup(html,'html.parser')
first_li=soup.find('li')
print('first_li',first_li)
print('first_li(返回的标签内容):',first_li.text)
print('first_li(返回的标签属性):',first_li.attrs)
print('first_li.string(返回的标签字符串):',first_li.string)
find方法也可以通过“属性=值”的方法对指定标签进行查找
second_li=soup.find('li',class_='girl1')
print('second_li',second_li)
tips:
“class”是python的保留关键字,在查找class属性时可以采用以下两种方法
#使用BeautifulSoup自带关键字 class_
second_li=soup.find('li',class_='girl1')
#以字典形式进行参数传递
second_li=soup.find('li',attrs={'class':'girl1'})
find_all方法
返回符合查找条件的所有标签
语法:
Find_all(name,attrs,recursive,text,limit,**kwargs)
比如,我们想要查找HTML文档中所有的girl信息,这些信息在<ul class=“girls”>下的多个<li>标签中
ul=soup.find('ul',class_='girls')
girls_info=ul.find_all('li')
print(girls_info)
以列表形式返回结果,列表中每一项为符合条件的标签。
3.例子
我们想要爬豆瓣排名前250的电影信息(电影名+链接)
发起请求,获取响应
#发起请求,获取响应,查看状态码
import requests
url='https://movie.douban.com/top250'
response=requests.get(url)
print(response)
状态码竟然是418,获取响应失败?
原因在于这个网站采用的反爬虫的手段。
打开浏览器-右击-检查(或审查元素)-Network,刷新网页会看到浏览器和服务器之间的多次请求,在请求Header中包含 User-Agent属性。
当我们通过爬虫程序对服务器进行访问时,该属性中会包含Python或Java的字样,很多网站都通过检查该属性值来判断 请求是否是从爬虫程序发出的,从而达到反爬虫的目的,这是反爬虫最简单但也很常用的的方法。
解决方法:从浏览器复制user-agent,更改爬虫程序的请求header信息,就可以搞定啦~
import requests
url='https://movie.douban.com/top250'
headers={
'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36'
}
response=requests.get(url,headers=headers)
print(response)
Response状态码为200,已经得到了网页的HTML文档,接下来需要从其中获取想要的电影名和链接。
解析内容
在网页中按照下图1,2,3操作,可以在文档中找到”肖申克的救赎“所在的位置。
《肖申克的救赎》所有信息在<ol class="grid_view">下的第一个<li>标签中,其他的电影信息在后续的<li>标签。
另外电影名在<span class=“title”>中(第一个为中文名,第二个为英文名),链接在<a>标签中。
不多解释,直接上代码
html=response.text
from bs4 import BeautifulSoup
soup=BeautifulSoup(html,'html.parser')
movie_list=soup.find('ol',class_='grid_view')
movies=movie_list.find_all('li') #返回列表,包含页面中所有的电影
movie_names=[]
movie_urls=[]
for movie in movies:
name=movie.find('span',class_='title').get_text() #只拿到名字
movie_names.append(name)
url=movie.find('a')['href']
movie_urls.append(url)
for name,url in zip(movie_names,movie_urls):
print(name,':',url)
部分结果如下,已经得到第一页的TOP25电影信息
网页翻页
想要得到Top250的电影信息,需要用程序控制网页翻页,一种方法是通过观察网页url,发现每页只是start=XX值不同,并且有规律可循。
修改程序,可以得到TOP250的电影信息啦~
import requests
from bs4 import BeautifulSoup
movie_names=[]
movie_urls=[]
url_start='https://movie.douban.com/top250?start='
url_end='&filter='
for i in range(0,226,25):
url_mid=str(i)
url=url_start+url_mid+url_end
headers={
'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36'
}
response=requests.get(url,headers=headers)
soup=BeautifulSoup(html,'html.parser')
movie_list=soup.find('ol',class_='grid_view')
movies=movie_list.find_all('li')
for movie in movies:
name=movie.find('span',class_='title').get_text() #只拿到名字
movie_names.append(name)
for movie in movies:
url=movie.find('a')['href']
movie_urls.append(url)
for name,url in zip(movie_names,movie_urls):
print(name,':',url)
三、正则表达式
正则表达式是对字符串操作的逻辑公式,用事先定义好的特定字符或这些字符的组合构造“规则字符串”,用“规则字符串”来查找“给定字符串”是否含有某种子串。
python中的正则表达式,通过内置的“re”模块实现。
1.常用的匹配模式
PS:可以先跳过表格,例子中应用时,再回到表格对照
2.re方法
patten:模板
content:待查找的字符串
比如,用patten匹配字符串中的两个连续的数字
import re
content1="fdifngidngogdikf89109101d"
content2="10dingpng90"
patten='\d{2}' #正则表达式的匹配规则是否有两个连续的数字
res_search=re.search(patten,content1)
res_findall=re.findall(patten,content1)
res_match1=re.match(patten,content1)
res_match2=re.match(patten,content2)
print('res_search(content1):',res_search)
print('res_findall(content1):',res_findall)
print('res_match(content1):',res_match1)
print('res_match(content2):',res_match2)
想要匹配字符串找 年-月-日 ,其中年为4位数字,月和日都为1位或2位数字。
content='1996-01-02dosgngo1996-1-2jaognhld1989-01-02'
patten='\d{4}-\d{1,2}-\d{1,2}'
res=re.findall(patten,content) #从字符串任意位置匹配
print(res)
想要把查找的内容中的一部分取出来,如 想要单独得到年和月,可以重新定义patten,将需要的内容放在()中
patten='(\d{4})-(\d{1,2})-\d{1,2}'
res3=re.search(patten,content)
print(res3)
print('Year:',res3.group(1))
print('Month',res3.group(2))
3.例子
同样是爬取豆瓣TOP250的电影信息
在得到html文档后,在文档中找到包含电影名和链接的标签,制定正则表达式规则对想要的内容进行检索。
编写正则表达式规则
patten='<div.*?hd.*?href="(.*?)".*?title">(.*?)</span>'
#.*?表示任意字符串,把想要得到的电影名和链接放到()中
详细代码如下:
#利用正则化方法获取豆瓣电影TOP250
import requests
import re
movie_names=[]
movie_urls=[]
url_start='https://movie.douban.com/top250?start='
url_end='&filter='
patten='<div.*?hd.*?href="(.*?)".*?title">(.*?)</span>'
for i in range(0,226,25):
url_mid=str(i)
url=url_start+url_mid+url_end
headers={
'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36'
}
response=requests.get(url,headers=headers)
html=response.text
results=re.findall(patten,html,re.S)
for result in results:
url,name=result
movie_names.append(name)
movie_urls.append(url)
for name,url in zip(movie_names,movie_urls):
print(name,':',url)
四、总结
《项目实战 | python爬虫概述及实践(一)》中介绍了网络爬虫的定义、分类和基本流程(发起请求、获取响应内容、解析内容、保存数据)。
本篇文章为 python爬虫概述与实践的第二篇文章,主要介绍了BeautifulSoup和正则化方法,用于从服务器响应的HTML文档中解析提取想要的信息。
后续连载文章会继续分享python爬虫相关内容,感兴趣记得关注“程序媛驿站”,记得关注每周更新的“python爬虫概述与实践”
作者:balabala
编辑:葡萄媛