本博客通过爬取猫眼票房Top100来简要复习一下网页的HTML获取(requests库)解析(Beautiful Soup库)和数据保存(csv库)以及总结一下爬取过程中遇到的问题和解决方法
运行结果如下


1.获取网页源代码
def get_one_page(url):headers={'User-Agent':'your_UA','Cookie':'your_cookie'}try:response=requests.get(url,headers=headers)response.raise_for_status() response.encoding=html.apparent_encodingreturn response.textexcept:return "产生异常"
获取网页HTML用的是requests库的get方法
获取网页最简单的方法就是:
response=requests.get(url)
get方法返回的是Response对象这是一个非常重要的对象有以下重要的属性:
| 属性 | 说明 |
|---|---|
| r.status_code | HTTP请求返回状态,200成功,404失败 |
| r.text | HTTP响应内容的字符串形式 |
| r.encoding | 从HTTP header中猜测出的响应内容编码方式 |
| r.apparent_encoding | 从内容中分析出的响应内容编码方式(备选编码) |
| r.content | HTTP响应内容的二进制形式 |
一般网站都有反爬虫措施,可以识别出这是爬虫从而返回一些奇奇怪怪的东西而这些字符串并不是我们想要的网页源代码,因此我们要在请求中添加请求头来伪装浏览器,请求头通过get方法的headers参数引入
response= requests.get(url,headers=headers)
headers参数接受一个字典,其中可以包括Cookie,User-Agent等信息
get方法还可以接受timeout参数来限定请求的时间(超过时间抛出异常)
爬取网页并不是每次都一定能成功的,因此异常处理十分重要,可以通过try-except语句来捕获异常
Response对象的raise_for_status 方法是专门与异常打交道的方法如果返回的状态码不是200,将产生异常requests.HTTPError
apparent_encoding是从响应内容中分析出的编码方式,一般比encoding更加可靠所以用apparent_encoding来替换encoding
以上是爬取网页的通用代码框架
2.解析HTML文档提取相关信息并保存
第一步成功返回了网页源代码接下来要做的就是解析提取信息并保存到本地,这一步用到的是bs4库中的BeautifulSoup对象和csv库
def parse_one_html(html):soup=BeautifulSoup(html,'lxml')names=soup.find_all('p',attrs={'class':"name"})name_list=[]for item in names:name_list.append(item.string)times=soup.find_all('p',attrs={'class':'releasetime'})time_list=[]for item in times:time_list.append(item.string.strip())starts=soup.find_all('p',attrs={'class':'star'})start_list=[]for item in starts:start_list.append(item.string.strip())with open('top100.csv','a',encoding='utf-8') as f:writer=csv.writer(f)for name,time,start in zip(name_list,time_list,start_list):writer.writerow([name,time,start])
解析提取
要提取信息首先就要初始化一个BeautifulSoup对象
soup=BeautifulSoup(html,‘lxml’)
该对象的第一个参数是带解析的HTML字符串,第二个参数是解析器的类型
对于不标准的HTML字符串初始化的时候BeautifulSoup可以自动更正
BeautifulSoup有prettify() 方法可以解析字符串以标准格式输出
直接调用节点名称就可以选择节点元素( bs4.element.Tag类型)
这样子选择只能选择满足条件的第一个节点,要想获取全部节点可以使用find_all() 方法
list=BeautifulSoup.find_all(name,attrs,**kwargs)
name:要查找节点的名称;attrs:节点的属性值,是一个字典
这个方法返回的是一个列表,列表中的每个元素都是满足要求的节点元素
( bs4.element.Tag类型)访问列表就可以得到每个元素的内容
因为返回的是bs4.element.Tag类型所以还可以继续调用节点名称进行嵌套查找
对于bs4.element.Tag类型有以下操作
1.获取名称
可以使用name属性来获取节点名称,例如:
print(soup.title.name)
#运行结果 title
2.获取属性
每个节点可能有多个属性,选择这个节点后可以调用attrs获取所有属性
print(soup.p.attrs)
print(soup.p.attrs['name'])
attrs的返回结果是字典形式
3.获取内容
可以利用string属性获取节点元素包含的文本内容,比如要获取第一个p节点的文本内容:
print(soup.p.string)
保存文件
with open('top100.csv','a',encoding='utf-8') as f:writer=csv.writer(f)for name,time,start in zip(name_list,time_list,start_list):writer.writerow([name,time,start])
with as可以简化写法,在with控制块结束时文件会自动关闭,所以就不需要再调用close()方法
首先,打开top100.csv文件,然后指定打开模式为’a’(即追加),获得文件句柄,随后调用csv库的writer()方法初始化写入对象,传入该句柄,然后调用writerow()方法传入每行的数据即可完成写入
补充:关于zip()函数
zip函数的原型为:zip([iterable, …])
参数iterable为可迭代的对象,并且可以有多个参数。该函数返回一个以元组为元素的列表,其中第 i 个元组包含每个参数序列的第 i 个元素。返回的列表长度被截断为最短的参数序列的长度。只有一个序列参数时,它返回一个1元组的列表。没有参数时,它返回一个空的列表。
完整代码
import time
from lxml import etree
import requests
from bs4 import BeautifulSoup
import csvdef get_one_page(url):headers={'User-Agent':'your_UA','Cookie':'your_Cookie'}html=requests.get(url,headers=headers)try :html.raise_for_status()html.encoding=html.apparent_encodingreturn html.textexcept:return Nonedef parse_one_html(html):soup=BeautifulSoup(html,'lxml')names=soup.find_all('p',attrs={'class':"name"})name_list=[]for item in names:name_list.append(item.string)times=soup.find_all('p',attrs={'class':'releasetime'})time_list=[]for item in times:time_list.append(item.string.strip()[5:])starts=soup.find_all('p',attrs={'class':'star'})start_list=[]for item in starts:start_list.append(item.string.strip()[3:])with open('top100.csv','a',encoding='utf-8') as f:writer=csv.writer(f)for name,time,start in zip(name_list,time_list,start_list):writer.writerow([name,time,start])if __name__=='__main__':offset=10with open('top100.csv','w',encoding='utf-8') as f:writer=csv.writer(f)writer.writerow(['片名','时间','主演'])for i in range(10):url='https://maoyan.com/board/4?requestCode=b19e676ce53b36a2ad23f2e2c48c7e39ynijn&offset='+str(i*offset)html=get_one_page(url)parse_one_html(html)time.sleep(1)













