HTML正文抽取
本例主要将HTML正文存储为两种格式:JSON和CSV。
首先有一点需要说明,这是一个静态网站,标题,章节,章节名称。
存储为JSON
当成功获取标题,章节,接下来将数据存储为JSON.
JSON文件的操作分为编码和解码,通过JSON模块来实现。
编码过程是吧Python对象转化成JSON对象的一个过程,常用的两个函数dumps和dump函数。
两个函数唯一区别是dump把Python对象转换成JSON对象,并将JSON对象通过fp文件流写入文件中,而dumps则是生成了一个字符串。
dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,allow_nan=True, cls=None, indent=None, separators=None, encoding='utf-8', default=None, sort_keys=False, **kw)
dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,allow_nan=True, cls=None, indent=None, separators=None, encoding='utf-8', default=None, sort_keys=False, **kw)
常用参数:
Skipkeys:默认值是False。如果dict的keys内的数据不是python的基本类型(str, unicode, int ,long, flag ,bool ,None),设置为False时,就会报TypeError错误。设置为True则会跳过这类
ensure_ascii:默认值True。如果dict内含有非ASCII的字符,则会以类似'\uXXXX'的格式显示数据,设置成False后,救恩那个正常显示。
indent:应该是一个非负的整形,如果是0,或者为空,则一行显示数据,否则会换行且按照indent的数量显示前面的空白,将JSON内容进行格式化显示。
separators:分隔符,实际上是(item_separator, dict_separator)是一个元组,默认的就是(',',';'),这表示dictionary内keys之间用','隔开,而key和value之间用';'隔开。
encoding:默认UTF-8,设置JSON数据的编码方式
sort_keys:将数据根据keys的值进行排序。
解码过程是把json对象转换成python对象的一个过程,常用的两个函数是load和loads函数
loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
常用参数:
encoding:指定编码格式
parse_float:如果指定,将把每一个JSON字符串按照float解码调用。默认情况下 相当于float(num_str)
parse_int:如果指定,将把每一个JSON字符串按照int解码调用。默认情况下,相当于int(num_str)
import json
import requests
from bs4 import BeautifulSoup
url = 'https://www.bbiquge.net/book/451/'
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.33'
headers = {
'User-Agent': user_agent
}
r = requests.get(url, headers=headers)
soup = BeautifulSoup(r.text, 'html.parser')
content = []
for list in soup.select('.zjlist'):
h2 = list.find('h2')
if h2 is not None:
h2_title = h2.string
arr = []
for a in list.find_all('dd'):
txtUrl = a.find('a').get('href')
txtTitle = a.find('a').string
arr.append({"box_title": txtTitle, "url": url + txtUrl})
content.append({"title": h2_title, "content": arr})
print(str(content))
with open('dmbj.json', 'w', encoding='utf-8') as fp:
json.dump(content, fp=fp, ensure_ascii=False, indent=4)
存储为CSV
其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列。
CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段间的分隔符是其他字符或字符串。
多媒体文件抽取
存储文件有两种方式:只获取文件的URL链接或者直接将媒体文件下载到本地。
urllib模块提供了urlretrieve()函数。可以直接将远程数据下载到本地
urlretrieve(url, filename=None, reporthook=None, data=None)
参数说明:
filename:指定了存储的本地路径。
reporthook:一个回调函数,当连接上服务器以及相应的数据块传输完毕会触发该回调函数。
data:只发送到服务器的数据,该方法返回一个包含两个元素的(filename, headers)元组,filename表示保存到本地的路径,header表示服务器的响应头。
import csv
headers = ['ID', 'UserName', 'Password', 'Age', 'Country']
rows = [
{1001, 'qiye', 'qiye_pass', 24, 'China'},
{1002, 'mary', 'mary_pass', 20, 'USA'},
]
with open('qiye.csv', 'w') as f:
f_csv = csv.writer(f)
f_csv.writerow(headers)
f_csv.writerows(rows)
with open('qiye.csv', 'r') as f:
f_csv = csv.reader(f)
headers = next(f_csv)
for row in f_csv:
print(row)
Email提醒
发送邮件的协议是STMP,Python内置对SMTP的支持,可以发送纯文本邮件,HTML邮件以及带附件的邮件。
Python对SMTP支持有smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件。
这里用163邮件,开启SMTP功能。
纯文本邮件:
msg = MIMEText('msg', 'plain', 'utf-8')
MIMEText的3个参数:
邮件正文
MIME的subtype,传入plain 表示纯文本,最终的MIME就是 ’textplain‘
设置编码格式
接着设置邮件的发件人,收件人,主题等信息,并通过STMP发送出去。
from email.mime.text import MIMEText
from email.header import Header
from email.utils import parseaddr, formataddr
import smtplib
def _format_adds(s):
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))
# 发
from_addr = 'xxxxx@163.com'
# 密码
password = 'xxxxx'
# 收
to_addr = 'xxxxx@qq.com'
# 163 网易邮件服务其地址
smtp_server = 'smtp.163.com'
# 设置邮件信息
msg = MIMEText('Python 爬虫运行异常, 异常信息为遇到HTTP 403', 'plain', 'utf-8')
msg['From'] = _format_adds('一号爬虫 <%s>' % from_addr)
msg['To'] = _format_adds('管理员 <%s>' % to_addr)
msg['Subject'] = Header('一号爬虫运行状态', 'utf-8').encode()
# 发送邮件
server = smtplib.SMTP(smtp_server, 25)
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()