python爬虫阶段性总结和项目实操——爬取猫眼票房Top100

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


# 1.获取网页源代码
```python
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_encoding
return response.text
except:
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库**
```python
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**属性来获取节点名称,例如:
```python
print(soup.title.name)
#运行结果 title
```
#### 2.获取属性
每个节点可能有多个属性,选择这个节点后可以调用**attrs**获取所有属性
```python
print(soup.p.attrs)
print(soup.p.attrs['name'])
```
attrs的返回结果是**字典形式**
#### 3.获取内容
可以利用**string**属性获取节点元素包含的文本内容,比如要获取第一个p节点的文本内容:
```python
print(soup.p.string)
```
## 保存文件
```python
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元组的列表。没有参数时,它返回一个空的列表。


### 完整代码
```python
import time
from lxml import etree
import requests
from bs4 import BeautifulSoup
import csv

def 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_encoding
return html.text
except:
return None

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()[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=10
with 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)
```

上一篇:Linux搭建docker


下一篇:Linux下Fork与Exec使用