一.基本原理
爬虫即网络爬虫,英文是Web Spider。翻译过来就是网络上爬行的蜘蛛,如果把互联网看作一张大网,那么爬虫就是在大网上爬来爬去的蜘蛛,碰到想要的食物,就把他抓取出来。
我们在浏览器中输入一个网址,敲击回车,看到网站的页面信息。这就是浏览器请求了网站的服务器,获取到网络资源。那么,爬虫也相当于模拟浏览器发送请求,获得到HTML代码。HTML代码里通常包含了标签和文字信息,我们就从中提取到我们想要的信息。
通常爬虫是从某个网站的某个页面开始,爬取这个页面的内容,找到网页中的其他链接地址,然后从这个地址爬到下一个页面,这样一直不停的爬下去,进去批量的抓取信息。那么,我们可以看出网络爬虫就是一个不停爬取网页抓取信息的程序。
爬虫的工作流程
1.发起请求:
通过HTTP库向目标站点发起请求,即发送一个Request,请求可以包含额外的headers等信息,然后等待服务器响应。这个请求的过程就像我们打开浏览器,在浏览器地址栏输入网址:www.baidu.com,然后点击回车。这个过程其实就相当于浏览器作为一个浏览的客户端,向服务器端发送了 一次请求。
2.获取响应内容:
如果服务器能正常响应,我们会得到一个Response,Response的内容便是所要获取的内容,类型可能有HTML、Json字符串,二进制数据(图片,视频等)等类型。这个过程就是服务器接收客户端的请求,进过解析发送给浏览器的网页HTML文件。
3.解析内容:
得到的内容可能是HTML,可以使用正则表达式,网页解析库进行解析。也可能是Json,可以直接转为Json对象解析。可能是二进制数据,可以做保存或者进一步处理。这一步相当于浏览器把服务器端的文件获取到本地,再进行解释并且展现出来。
4.保存数据:
保存的方式可以是把数据存为文本,也可以把数据保存到数据库,或者保存为特定的jpg,mp4 等格式的文件。这就相当于我们在浏览网页时,下载了网页上的图片或者视频。
二.实战干货
1.request 包
request基于urllib3,整合了urllib系列的常用操作,非常方便
代码示例:
import requests
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'}
response = requests.get('http://www.baidu.com', headers=headers)
print(response.text)
释义:
- 添加headers是因为有些网页会禁止爬虫的访问,检查是否是浏览器访问。这个时候我们就要给爬虫加一个headers,加一个浏览器的user-agent信息。(user-agent可以在任意浏览器打开 ‘developer tools’,中文版似乎是叫‘审查元素’?,然后点任意页面,在‘network’选项,request header下有 user-agent字段)
- response可以得到的信息:response.status_code # 状态码 response.text # 网页源码 response.headers # 头部信息 response.cookies # Cookie response.url # 请求的url response.history # 访问的历史记录
PS:可以使用POST方法传参(在能传参的页面)
2.使用request下载图片
import requests
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'}
response = requests.get('ttps://www.baidu.com/img/baidu_jgylogo3.gif', headers=headers)
with open('logo.jpg', 'wb') as f:
f.write(response.content)
3.使用request.post上传图片
import requests
files = {'file' : open('logo.jpg','rb')}
resp = requests.post('http://httpbin.org/post', files=files)
print(resp.text)
把刚刚下载的logo.jpg传到 http://httpbin.org 虽然我并没发现这样子传上去会对httpbin这个网页造成什么影响,但是回显的response还是很清楚的可以看到图片的字节流的。个人学艺不精的感觉,post方法应该主要是用于提交表单/登陆等操作。
4.使用BeautifulSoup解析网页
beautifulSoup可以提供很多便捷的方法,可以直接搜索网页中我们需要的内容。下面是BS的基本用法:
from bs4 import BeautifulSoup
import lxml
import requests
html_doc = requests.get('https://book.douban.com/top250?start=0')
soup = BeautifulSoup(html_doc.text,'lxml')
div = soup.find_all("div", class_ = 'pl2')
for item in div:
print(item.find('a')['title'])
打印出豆瓣排行页面的全部书名
把豆瓣书名+作者+评分等全部输出的完整代码:
自己练手的辣鸡版本~
from bs4 import BeautifulSoup
import lxml
import requests
html_doc = requests.get('https://book.douban.com/top250?start=0')
soup = BeautifulSoup(html_doc.text,'lxml')
div = soup.find_all("div", class_ = 'pl2')
names = [a.find('a')['title'] for a in div]
s = soup.find_all('span', class_ = 'rating_nums')
scores = [sco.get_text() for sco in s]
dis = soup.find_all('span', class_ = 'inq')
quotes = [d.get_text() for d in dis]
with open('小测试.txt', 'w', encoding='utf-8') as f:
for name, score, quote in zip(names,scores, quotes):
name = '书名:' + name + '\n'
score = '评分:' + score +'\n'
quote = '箴言:' +quote + '\n'
data = name + score + quote
f.writelines(data + '=======================' + '\n')
生成的txt效果:
大神的教学版本:
# -*- coding:utf-8 -*-
# author: yukun
import requests
from bs4 import BeautifulSoup
# 发出请求获得HTML源码的函数
def get_html(url):
# 伪装成浏览器访问
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'}
resp = requests.get(url, headers=headers).text
return resp
# 解析页面,获得数据信息
def html_parse():
# 调用函数,for循环迭代出所有页面
for url in all_page():
# BeautifulSoup的解析
soup = BeautifulSoup(get_html(url), 'lxml')
# 书名
alldiv = soup.find_all('div', class_='pl2')
names = [a.find('a')['title'] for a in alldiv]
# 作者
allp = soup.find_all('p', class_='pl')
authors = [p.get_text() for p in allp]
# 评分
starspan = soup.find_all('span', class_='rating_nums')
scores = [s.get_text() for s in starspan]
# 简介
sumspan = soup.find_all('span', class_='inq')
sums = [i.get_text() for i in sumspan]
for name, author, score, sum in zip(names, authors, scores, sums):
name = '书名:' + str(name) + '\n'
author = '作者:' + str(author) + '\n'
score = '评分:' + str(score) + '\n'
sum = '简介:' + str(sum) + '\n'
data = name + author + score + sum
# 保存数据
f.writelines(data + '=======================' + '\n')
# 获得所有页面的函数
def all_page():
base_url = 'https://book.douban.com/top250?start='
urllist = []
# 从0到225,间隔25的数组
for page in range(0, 250, 25):
allurl = base_url + str(page)
urllist.append(allurl)
return urllist
# 文件名
filename = '豆瓣图书Top250.txt'
# 保存文件操作
f = open(filename, 'w', encoding='utf-8')
# 调用函数
html_parse()
f.close()
print('保存成功。')
差异:除了教学版本里使用了比较优雅的编码方式和合适的方法封装之外,我自己只打印了 https://book.douban.com/top250?start=
0的第一页的内容,大神遍历了所有250本书。向大神致敬!(学习链接最下面附上)
PS:豆瓣的TOP250因为页数是固定的,可以写成固定值,如果要爬取的页面数量是不固定的,可以用如下方法获取总的页数:
# so为传入的soup,这里的例子是获取的豆瓣TOP250页数
def get_pages(so):
pages = so.find('div', class_ = 'paginator')
page = [p.get_text() for p in pages.find_all('a')]
return len(page)