文章目录
Python学习
爬虫
一、概述
爬虫就是一段自动抓取互联网信息的程序,从互联网上抓取对于我们有价值的信息。
二、架构
- 调度器:相当于一台电脑的CPU,主要负责调度URL管理器、下载器、解析器之间的协调工作。
- URL管理器:包括待爬取的URL地址和已爬取的URL地址,防止重复抓取URL和循环抓取URL,实现URL管理器主要用三种方式,通过内存、数据库、缓存数据库来实现。
- 网页下载器:通过传入一个URL地址来下载网页,将网页转换成一个字符串,网页下载器有urllib2(Python官方基础模块)包括需要登录、代理、和cookie,requests(第三方包)
- 网页解析器:将一个网页字符串进行解析,可以按照我们的要求来提取出我们有用的信息,也可以根据DOM树的解析方式来解析。网页解析器有正则表达式(直观,将网页转成字符串通过模糊匹配的方式来提取有价值的信息,当文档比较复杂的时候,该方法提取数据的时候就会非常的困难)、html.parser(Python自带的)、beautifulsoup(第三方插件,可以使用Python自带的html.parser进行解析,也可以使用lxml进行解析,相对于其他几种来说要强大一些)、lxml(第三方插件,可以解析 xml 和 HTML),html.parser 和 beautifulsoup 以及 lxml 都是以 DOM 树的方式进行解析的。
- 应用程序:就是从网页中提取的有用数据组成的一个应用。
三、基本流程
1. 准备工作
-
通过浏览器的开发者工具分析网页,在Elements下找到需要的数据位置;
-
引入和网页爬虫相关的模块
bs4:bs4是一个可以从HTML或XML文件中提取数据的Python库.
xlwt:进行excel操作
re:re 模块使 Python 语言拥有全部的正则表达式功能
urllib:urllib是python内置的HTTP请求库
sqlite3:进行sqlite数据库操作
下载bs4模块:
下载xlwt模块:
2. 获取数据(urllib)
一般使用 urllib 库获取页面数据,它是python内置的HTTP请求库,无需安装即可使用,它包含了4个模块:
- request:它是最基本的http请求模块,用来模拟发送请求;
- error:异常处理模块,如果出现错误可以捕获这些异常;
- parse:一个工具模块,提供了许多URL处理方法,如:拆分、解析、合并等;
- robotparser:主要用来识别网站的robots.txt文件,然后判断哪些网站可以爬。
- 获取get请求
示例一:
import urllib.request
class GetHtml(object):
def __init__(self,URL):
self.url = URL
def get_index_get(self):
self.response = urllib.request.urlopen(self.url)
return self.response.read()
test_html = GetHtml("http://www.baidu.com")
print(test_html.get_index_get())
运行结果:
使用utf-8解码:
response.read().decode('utf-8')
运行结果:百度的网页源代码
示例二:get请求的超时处理
import urllib.request
class GetHtml(object):
def __init__(self,URL):
self.url = URL
def get_index_getTimeout(self):
try:
self.response = urllib.request.urlopen(self.url,timeout=0.01)
print(self.response.read().decode("utf-8"))
except urllib.error.URLError as e:
print("Time Out!")
test_html = GetHtml("http://httpbin.org/get")
print(test_html.get_index_getTimeout())
运行结果:
示例三:
# 获取get请求
import urllib.request
class GetHtml(object):
def __init__(self,URL):
self.url = URL
def get_index_get(self):
self.response = urllib.request.urlopen(self.url)
return self.response.read().decode('utf-8')
def get_index_post(self):
data = bytes(urllib.parse.urlencode({"hello":"world"}),encoding="utf-8")
self.response = urllib.request.urlopen(self.url,data= data)
return self.response.read().decode('utf-8')
def get_index_getTimeout(self):
try:
self.response = urllib.request.urlopen(self.url,timeout=0.01)
print(self.response.read().decode("utf-8"))
except urllib.error.URLError as e:
print("Time Out!")
def get_index(self):
self.response = urllib.request.urlopen(self.url)
# return self.response.status 获取状态码
return self.response.getheaders() # 获取response headers信息
# return self.response.getheaders("具体的信息")
test_html = GetHtml("http://www.baidu.com")
print(test_html.get_index())
示例四:使用urllib.request.Request封装
import urllib.request
response = urllib.request.urlopen("http://www.douban.com")
print(response.read().decode("utf-8"))
# 运行结果:418错误,urllib.error.HTTPError: HTTP Error 418:
# 原因该网站对python请求的方式做限制
修改User-Agent,封装url和header:
url="http://www.douban.com"
headers = {
"User-Agent": Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
}
req = urllib.request.Request(url=url,headers=headers)
response = urllib.request.open(url)
print(response.read().decode("utf-8"))
运行结果:可以获取
- 获取post请求
httpbin.org 这个网站能测试 HTTP 请求和响应的各种信息,比如 cookie、ip、headers 和登录验证等,且支持 GET、POST 等多种方法。
post方式必须传递一些表单信息。
import urllib.request
class GetHtml(object):
def __init__(self,URL):
self.url = URL
def get_index_post(self):
data = bytes(urllib.parse.urlencode({"hello":"world"}),encoding="utf-8")
self.response = urllib.request.urlopen(self.url,data= data)
return self.response.read().decode('utf-8')
test_html = GetHtml("http://httpbin.org/post")
print(test_html.get_index_post())
urllib.parse.urlencode里面可以传递用户名密码、cookie等。
运行结果:
3. 解析内容(BeautifulSoup)
- 标签解析:
使用BeautifulSoup定位特定的标签位置。
BeautifulSoup模块的使用:
# 1. 导入BeautifulSoup库
from bs4 import BeautifulSoup
# 2. 解析内容
soup = BeautifulSoup(html_doc)
# 3. 浏览数据
soup.title # 获取包含title标签的title
soup.title.string # 获取title的内容
# 4. 正则使用
soup.find_all(name='x', attrs={'xx':re.compile('xxx')})
- 正则提取:
用来检索、替换某些符合规则的文本,python中使用re模块操作正则表达式。
示例:爬取豆瓣的电影链接
1)从开发者工具查找标签信息
2)定义搜索链接定义规则,先将所有的div的class="item"过滤出来
from bs4 import BeautifulSoup
# 获取get请求
import urllib.request
url="https://movie.douban.com/top250"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
}
req = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(req)
# 使用html.parser解析器
soup = BeautifulSoup(response.read().decode('utf-8'),"html.parser")
# 查找符合要求的字符串,一层一层定义 div 下的 item
for item in soup.find_all('div',class_="item"):
print(item)
运行结果:
3)定义规则过滤链接
from bs4 import BeautifulSoup
# 获取get请求
import urllib.request
import re
url="https://movie.douban.com/top250"
# 定义规则
findLink = re.compile(r'<a href="(.*?)">')
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
}
req = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(req)
# print(response.read().decode('utf-8'))
soup = BeautifulSoup(response.read().decode('utf-8'),"html.parser")
for item in soup.find_all('div',class_="item"):
# 保存爬取信息
data = []
item = str(item)
link = re.findall(findLink,item)[0]
data.append(link)
print(data)
运行结果:
4. 保存内容
通过xlwt、sqlite3等模块将爬取的内容保存至excel或数据库中。
四、正则表达式
1. 概述
正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配,re 模块使 Python 语言拥有全部的正则表达式功能。正则语法和之前学习的一样,只不过不同的语言通过不同的工具使用而已。
2. re模块的部分方法
- match和search
# 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
re.match(pattern, string, flags=0)
# 扫描整个字符串并返回第一个成功的匹配
re.search(pattern, string, flags=0)
# 参数:
pattern:匹配的正则表达式
string:要匹配的字符串。
flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
- 注意:re.match()和re.search()区别
re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,而 re.search 匹配整个字符串,直到找到一个匹配。
- sub
用于替换字符串中的匹配项。
re.sub(pattern, repl, string, count=0, flags=0)
# 参数:
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
flags : 编译时用的匹配模式,数字形式。
- findall
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
re.findall(pattern, string, flags=0)
- 注意:
match 和 search 是匹配一次 findall 匹配所有。
- compile
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。
re.compile(pattern,flags)
# 参数
pattern : 一个字符串形式的正则表达式
flags : 可选,表示匹配模式,比如忽略大小写,多行模式等
五、示例
1. 爬取网页课程名称
爬取 ichunqiu 课程名称,抓包分析为POST请求,共有19页,页数由pageIndex变量控制,定制headers并传入data进行爬取:
import requests
import json
import _thread
import time
def get_lesson_name(data):
url = "https://www.ichunqiu.com/courses/ajaxCourses"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'
}
r = requests.post(url=url, headers=headers, data=data)
datas = json.loads(r.text)
name_long = len(datas['course']['result'])
for i in range(name_long):
print(datas['course']['result'][i]['courseName'])
if __name__ == '__main__':
for i in range(1, 20):
data = {
'courseTag': '',
'courseDiffcuty': '',
'IsExp': '',
'producerId': '',
'orderField': '',
'orderDirection': '',
'pageIndex': str(i),
'tagType': '',
'isOpen': ''
}
_thread.start_new_thread(get_lesson_name, (data,))
time.sleep(0.5)
# python3中使用 _thread模块开启线程:start_new_thread(function, args, kwargs=None)(方法名,参数必须是元组形式)
# 使用_thread不能控制控制线程数,必须加sleep休眠时间
运行结果:
2. 爬虫下载图片
"""
1. 通过正则表达式匹配所有的图片url
2. 通过for循环将获取的图片url列表存入新的列表并拼接上完整的图片下载url
3. 使用write方法将爬下的完整
"""
# 正则表达式 re模块
import urllib.request
import re
class GetHtml(object):
def __init__(self,URL,HEADER):
self.url = URL
self.header = HEADER
def get_index(self):
self.request = urllib.request.Request(self.url)
self.request.add_header("user-agent",self.header)
self.response = urllib.request.urlopen(self.url)
return self.response.read()
def get_list(self):
# 定义空列表用来存放图片下载的完整url
self.string_imglist = []
# 使用正则表达式匹配所有的图片url
self.imglist = re.findall("图片的scr的正则表达式.jpg",self.get_index())
# for循环拼接完整的下载路径
for i in self.imglist:
self.string_imglist.append(self.url+str(i,encoding="utf-8"))
print(self.imglist)
return self.string_imglist
def get_image(self):
# 下载图片:图片名为从1.jpg递增
num = 0
for self.url in self.get_list():
num += 1
with open(str(num) + ".jpg","wb") as f:
f.write(self.get_index())
test_html = GetHtml("网页地址","user-agent具体信息")
test_html.get_image()