爬虫的基础知识
文章目录
html 了解
要想对网页数据进行爬取,首先的了解一点html的知识,才能对我们爬取数据提供一个好的环境和平台
HBuilder的下载及安装
点击html下载官网根据以下步骤进行操作
第一步
第二步
第三步
第四步,安装
下载为一个压缩包,解压到自己想存放的路径,最后进行安装就ok了。
创建HTML项目
HTML 的基本知识
HTML: hyperText markup languagel,超文本标记语言
HTML的后缀名:
-
.html
-
.htm
HTML的两种标签名
-
一般标签:由起始标签和结束标签组成,可以插入其他标签或其他内容-,例如
<h1>yyds</h1>
-
自闭和标签:由起始标签组成,在起始标签末尾加斜杠,在中间不能加
入任何东西,例如:
<br />
注意:
- HTML中的标准是双引号
- HTML没有大小写之分
注释:与python不一样 html的注释为
在html中 ctrl+/
就能打印出来
格式化代码快捷键:ctrl + k
创建新的HTML会自动生成以下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
</body>
</html>
常用标签基本用法 注意标签之间的缩进
- 各个标签的用法
- 明白绝对路径和相对路径
<!-- 声明此文档为HTML5文档 -->
<!DOCTYPE html>
<!-- 定义了html文档 lang 表示中文-->
<html lang="zh">
<!-- 提供了需要定义的信息 -->
<head>
<!-- 元信息 -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- 定义了标题名 -->
<title>html基础</title>
<link rel="stylesheet" type="text/css" href="./css/style.css"/>
</head>
<!-- 在body标签写页面可见元素 -->
<body>
<!-- div:把不属于一类的标签间隔开 -->
<div class="a">
<!-- 标题标签:<h1>、<h2>....<h6> -->
<h1 id="a">我是标题标签h1</h1>
<h2>我是标题标签h2</h2>
<h6>我是标题标签h6</h6>
<!-- 段落标签:<p> -->
<p>YYDS</p>
<!-- 超链接标签<a> -->
<a href="https://www.baidu.com/" target='_blank'>百度</a>
<!-- 图像标签 <img /> -->
<img src=
"https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png" width="50px"/>
<!-- href和src区别 -->
<!-- href:负责引入超文本(HTML, CSS , JS) -->
<!-- src:负责引入一些资源(图片、音频、视频)并且将引入的资源嵌入到页面 -->
<img src="E:\新建文件夹\project\day21\img\4.jpg" width="60" height="80" />
<img src="./img/4.jpg" width="60" height="60" />
<!-- 绝对路径和相对路径 -->
<!-- 绝对路径:在电脑上资源盘下放的路径, 相对于电脑 -->
<!-- 相对路径:相对于当前文件所在目录, 寻找引入文件路径
./ 表示当前目录
../ 返回上一级-->
<img src="./../gril.jpg" width="250" height="400"/>
<!-- 音频文件:<audio> -->
<audio controls src="./music/1.m4a"></audio>
<!-- 视频文件<video> -->
<video controls src="./video/puppy_2.mp4"></video>
</div>
<div class="b">
<!-- 列表:有序列表和无序列表 -->
<ol>
<!-- 页面的用的是数字标记 -->
有序列表
<li>海王</li>
<li>甄嬛传</li>
<li>斗罗大陆</li>
</ol>
<ul>
<!-- 页面用的逗号标记-->
无序列表
<li>王者荣耀</li>
<li>摩尔庄园</li>
<li>和平精英</li>
</ul>
<!-- iframe框架:在当前页面嵌套一个新页面 -->
<iframe src="https://www.chinanews.com/" width="1000px" height="1000px"></iframe>
</div>
<div class="c">
<!-- 表格:<tbody> -->
<!-- tr:表格的行数 -->
<!-- th:表头 -->
<!-- td:存放内容的单元格 -->
<tbody>
<tr>
<th>队名</th>
<th>第一节</th>
<th>第二节</th>
<th>第三节</th>
<th>第四节</th>
<th>总分</th>
</tr>
<br />
<tr>
<td>太阳</td>
<td> 16</td>
<td>31</td>
<td>30</td>
<td>21</td>
<td>98</td>
</tr>
<br />
<tr>
<td>雄鹿</td>
<td>29</td>
<td>13</td>
<td>35</td>
<td>28</td>
<td>105</td>
</tr>
</tbody>
<!-- 换行标签 <br /> -->
<!-- 水平线标签 <hr /> -->
<hr />
<!-- 加粗标签 b,strong -->
<b>YYDS</b>
<strong>YYDS</strong>
<!-- 文字倾斜标签。i,em -->
<i>文字倾斜</i>
<em>文字倾斜</em>
<!-- 表单标签: <form> -->
<form>
账号:<input type="tell" /><br />
密码:<input type="password" /><br />
<input type="submit" value="登录" />
<input type="reset" value="重置" />
</form>
</div>
</body>
</html>
css用来修饰html
注释:ctrl+/
和HTML不一样 /*注释内容 */
css用于描述HMTL样式的编程语言
/* css引入分为:行内式、内嵌式、外链式 */
/ 通配符选择器 */
/* 通配符选择器 */
* {
/* 外边距 */
margin: none;
/* 内边距 */
padding: none;
}
/* 类选择器 */
.a {
/* 外部线框 */
/* 单实线 */
border: 10px solid red;
}
.b {
/* 双实线 */
border: 10px double blue;
}
.c {
/* dotted 虚线 */
border: 10px dotted green;
}
/* id选择器 */
#a {
/* 字体颜色 */
color: yellowgreen;
/* 字体样式 */
font-family: "楷体";
/* 字体尺寸 */
font-size: 20px;
}
/* 标签选择器 */
/* 将前端中标签选择器 */
/* 直接选择p标签 */
p {
font-size: 50px;
}
/* 父子选择器 */
/* 修改指定父标签下的某个子标签位置 */
.a>h2 {
/* 水平中间 */
text-align: center;
}
/* 后代选择器 */
.b li {
color: aquamarine;
}
/* 兄弟选择器 */
/* 和连接符左边的标签同级关系的下方所有标签都是他的兄弟 */
h1~h6 {
text-align: center;
}
/* 相邻兄弟选择器 */
/* 只能选择连接符左边的标签同级的相邻的下方的标签 */
h1+h2 {
font-family: "仿宋";
}
/* nth-child选择器 */
/* nth-child只根据同级关系查找 */
.b>ol>li:nth-child(2) {
color: red;
}
/* 属性选择器 */
input[type=submit] {
/* 背景颜色 */
background-color: darkseagreen;
/* 字体颜色 */
color: white;
/* 去掉边框 */
border: none;
}
form {
border: 2px solid black;
width: 450px;
/* margin-left: 500px; */
/* 修改外边距 默认 上右下左 */
margin: 20px 500px 30px 500px;
}
网页请求
import requests
用requests请求网页
状态码
200, 爬虫可用
403,访问的网站将爬虫封了
404,页面丢失
500,服务器出问题
请求豆瓣电影
import requests
import bs4
import selenium
from lxml import etree
import re
URL ='http://movie.douban.com/top250'
#headers用来伪装爬虫
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36'
}
resp =requests.get(url=URL, headers=headers)
print(resp.text)
with open('豆瓣电影.html','w',encoding='utf-8') as file:
file.write(resp.text)
with open('豆瓣电影.html','r',encoding='utf-8') as file:
content = file.read()
#print(content)
re_str = '<img width="100" alt="(.+)" src="(.+)" class="">'
result = re.search(re_str,content)
print(result)
#span()输出匹配到的字符串的起始位置和结束位置
print(result.span())
#group()将分组中的内容返回出来
# 如果参数是0 将所有分组的内容输出
print(result.group(1))#输出第一个分组
print(result.group(2))#输出第二个分组
# groups 将正则表达式中分组的内容合成一个元组
print(result.groups())
results2 = re.findall('<img width="100" alt="(.+)" src="(.+)" class="">',content)
for results in results2:
print(results)
requests的几种方法
import requests
import re
URL = 'https://wwwbaidu.com/'
#User-Agent: 将爬虫模拟成浏览器
#Cooike :存放的用户的账号密码信息
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36'
}
resp = requests.get(url=URL,headers=headers)
#状态码
#200,爬虫可用
#403,访问的网站将爬虫封了
#404,页面丢失
#500,服务器出问题
print(resp.status_code)
#打印访问的网址
print(resp.url)
#打印响应头:只需要记住'Content-Type'
print(resp.headers)
#打印响应头中提供的编码方式
#如果没有 ,默认选择ISO-8859-1:不能显示中文
print(resp.encoding)
#打印网页原代码中提供的编码方式
print(resp.apparent_encoding)
resp.encoding = resp.apparent_encoding
#文本流方式打印网页源码
print(resp.text)
# #以字节流(二进制)输出源码
# print(resp.content)
字符匹配的三种方式
re正则表达式
group(1)
#输出第一个分组
group(2)
#输出第二个分组
groups()
将正则表达式中分组的内容合成一个元组
爬取成都链家二手房信息
# 成都链家二手房信息
import requests
import re
URL = 'https://cd.lianjia.com/ershoufang/rs/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.73'
}
resp = requests.get(url=URL, headers=headers)
# print(resp.text)
li_str = re.compile('<li class="clear(.+?)</li>')
content = li_str.findall(resp.text)
# print(content, len(content))
for i in content:
# print(i)
# 房屋标题
title = re.compile(
'data-log_index="\d{1,2}" data-el="ershoufang" data-housecode="\d{12}" data-is_focus="" data-sl="">(.+?)</a>')
title_content = title.search(i)
title_1 = title_content.group(1)
print(title_1)
# 位置
area = re.compile(
'data-el="region">([\u4e00-\u9fa5]+([\u4e00-\u9fa5]+|\d+|[A-Z]+)[\u4e00-\u9fa5]+)[^\u4e00-\u9fa5]+([\u4e00-\u9fa5]+)</a>')
area_content = area.search(i)
x, y, z = area_content.groups()
print(f'{x}-{z}')
# 单价
unit_price = re.compile('<span>(单价\d+元/平米)</span>')
unit_price_1 = unit_price.search(i)
print(unit_price_1.group(1))
# 总价
total_price = re.compile('<span>(\d+\.?\d+)</span>万')
total_price_1 = total_price.search(i)
print(total_price_1.group(1) + '万')
print('*' * 10)
bs4
bs4 :全称 :Beautiful 4,可以从HTML或者XMl中提取数据。
请求过后使用bs4中的BeautifulSoup
方法
soup = bs4.BeautifulSoup(resp.text, 'lxml')
第一个参数是请求到的网页,第二给是解释方法
.text
提取标签中的内容
.attrs[]
提取标签中的链接
格式化爬取到的HTML源码
print(soup.prettify())
bs4用法
select
:使用(id、class、标签、属性、父子、后代、兄弟、相邻兄弟选择器等)去选择标签,返回的结果是一个列表
select_one
:使用(id、class、标签、属性、父子、后代、兄弟、相邻兄弟选择器等)去选择标签,,返回的结果是select结果中的第一个元素后代)
import bs4
# bs4 :全称 :Beautiful 4,可以从HTML或者XMl中提取数据。
html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
soup = bs4.BeautifulSoup(html,'lxml')
# print(soup,type(soup),sep='\n')
#格式化爬取到的HTML源码
print(soup.prettify())
print('--'*20)
#打印标签:只打印第一个某某标签的内容
# print(soup.head.title)
#打印标签的内容
# print(soup.head.title.string)
# print(soup.head.title.get_text())
# print(soup.head.title.text)
# print(soup.head.title.contents)
"""
The Dormouse's story
The Dormouse's story
The Dormouse's story
["The Dormouse's story"]
"""
# 选择标签内容方法:
# select:使用(id、class、标签、属性、父子、后代、兄弟、相邻兄弟选择器等)去选择标签,返回的结果是一个列表
# select_one:使用(id、class、标签、属性、父子、后代、兄弟、相邻兄弟选择器等)去选择标签,,返回的结果是select结果中的第一个元素后代)
p_list = soup.select('body > p')
print(p_list)
# p_list_1 = soup.select('body > .title')
# print(p_list_1)
#
p = soup.select_one('body > p')
print(p)
爬取中国新闻网标题及时间
# 中国新闻网当天新闻爬取
import requests
import bs4
import time
print(time.localtime())#现在的时间
flag = True
page = 1
while flag:
URL = f'https://www.chinanews.com/scroll-news/news{page}.html'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}
resp = requests.get(url=URL, headers=headers)
page += 1
print(resp.status_code)
resp.encoding = 'UTF-8'
# print(resp.text)
soup = bs4.BeautifulSoup(resp.text, 'lxml')
# print(soup)
li_list = soup.select('body > #content > #content_right > div.content_list > ul > li')
# print(li_list,len(li_list))
for i in li_list:
# print(i)
try:
localtime = time.localtime()
if f'{localtime.tm_mon}-{localtime.tm_mday}' == i.select_one('li > .dd_time').text[:-6]:
# 新闻类型
news_type = i.select_one('li > .dd_lm').text
# 新闻标题
news_title = i.select_one('li > .dd_bt > a').text
# 新闻链接
news_href = 'https:' + i.select_one('li > .dd_bt > a').attrs['href']
# 发布时间
news_time = i.select_one('li > .dd_time').text
print(news_type, news_title, news_href, news_time)
else:
flag = False
break
except Exception as err:
print(err)
selenium 自动化测试
from selenium import webdriver
# selenium,自动化测试
from selenium import webdriver
import time
URL = 'https://www.chinanews.com/scroll-news/news1.html'
URL1 = 'https://www.baidu.com/'
URL2 = 'https://www.taobao.com/'
# 创建浏览器对象
b = webdriver.Chrome('./chromedriver.exe')
# # 设置浏览器窗口大小
# b.set_window_size(1920, 1080)
# 将浏览器设置成全屏
# b.maximize_window()
# # 请求链接
b.get(URL)
# b.get(URL1)
# b.get(URL2)
#
# # 后退
# b.back()
# time.sleep(1)
# # 前进
# b.forward()
# # 打印网页源码:是字符串 --> bs4
# print(b.page_source, type(b.page_source))
#滚动滚动条
max_y = 4000
y = 0
while y <= max_y:
b.execute_script(f'window.scrollTo(0,{y})')
y += 1000
time.sleep(1)
# contents = b.find_element_by_id('content_right').text #包含下一级标签
# print(contents)
# news_title = b.find_elements_by_class_name('dd_bt') #同级标签是个列表
# for new in news_title:
# print(new.text)
# print(news_title)
# news_href = b.find_element_by_css_selector(
# '#content_right > div.content_list > ul > li > div.dd_bt > a').get_attribute('href')
# print(news_href)
# close()如果selenium打开了一个浏览器窗口,但是这个窗口有多个标签页,只关闭当前所在标签页;
# quit()直接关闭浏览器窗口;
# 浏览器打开时会产生缓存文件,close()只关闭浏览器,不执行清理缓存操作。quit()在关闭浏览器的同时会清理缓存。
b.close()
b.quit()
获取cookie
import time
from selenium import webdriver
URL = 'https://www.taobao.com/'
url2 = 'https://www.baidu.com/'
# 设置配置项
#options = webdriver.ChromeOptions()
#不加载图片提升速度
#options.add_argument('blink-settings=imagesEnabled=false')
#创建浏览器对象
b = webdriver.Chrome('./chromedriver.exe')
b.get(URL)
# 打开新的标签页
b.execute_script('window.open()')
# 输出选项卡
print(b.window_handles)
# 切换选项卡
b.switch_to.window(b.window_handles[1])
b.get(url2)
time.sleep(1)
#切换选项卡
b.switch_to.window(b.window_handles[0])
#点击登录选项
b.find_element_by_class_name('h').click()
b.find_element_by_class_name('icon-qrcode').click()
#隐式等待:全局等待方式
b.implicitly_wait(258)
# 检测信息是否被加载
b.find_element_by_class_name('site-nav-login-info-nick ')
# 获取cookie
cookie = b.get_cookies()
print(cookie)
# 保存cookie :数据的持久化
with open('cookie.txt','w') as file:
file.write(str(cookie))
b.quit()
请求淘宝
import time
from Tools.i18n.pygettext import safe_eval
from selenium import webdriver
#导入按键事件
from selenium.webdriver.common import keys
URL = 'https://www.taobao.com/'
#设置配置项
options = webdriver.ChromeOptions()
# 设置取消图片加载
options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})
with open('cookie.txt','r') as file:
cookie = file.read()
print(cookie)
new_cookie = safe_eval(cookie)
#创建浏览器对象
b = webdriver.Chrome('./chromedriver.exe', options=options)
# 防止selenium被监测
# 先修改js,再加载js
b.execute_cdp_cmd(
"Page.addScriptToEvaluateOnNewDocument",
{
"source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
}
)
#先访问淘宝页面 ,再传cookie
b.get(URL)
for i in new_cookie:
if i['secure']:
b.add_cookie(i)
# 再重新请求页面
b.get(URL)
# 定位搜索框
search = b.find_element_by_id('q').send_keys('三只松鼠大礼包')
# 定位搜索按钮
enter = b.find_element_by_class_name('btn-search').send_keys(keys.Keys.ENTER)
# 拖动进速度条
max_y = 5000
y = 0
while y <= max_y:
b.execute_script(f'window.scrollTo(0, {y})')
y += 1000
time.sleep(2)
print(b.page_source)#打印源码
代理IP
当请求过多的时候我们的IP可能会被封掉,此时就需要使用代理ip也就是用其他IP来请求
代理IP有专门的网站售卖,但不是所有的代理IP都行,所以我们要进行代理IP的检查
把下面代码装为一个包 check_proxies
"""
此代码为代理IP可用性检测模块,可准确筛选出尚未失效IP
注:
1.此代码只针对TXT数据格式接口。
2.尚未失效IP不一定为爬虫可用IP
3.使用时,请调用check_ip(url),url为TXT数据格式接口地址
"""
import requests
import telnetlib
import re
from concurrent.futures.thread import ThreadPoolExecutor
# 请求接口,匹配出代理IP,多线程检测
def check_ip(url):
real_ip = []
# 检测代理IP是否失效
def telnet_ip(ip, port):
try:
telnetlib.Telnet(ip, port, timeout=1)
real_ip.append(f'{ip}:{port}')
except:
pass
resp = requests.get(url)
ip_data = re.findall('(\d+\.\d+\.\d+\.\d+):(\d+)', resp.text)
with ThreadPoolExecutor(max_workers=16) as pool:
for ip, port in ip_data:
pool.submit(telnet_ip, ip, port)
return real_ip
检查代理IP
导入上面的包check_proxies
请求豆瓣电影
from check_proxies import check_ip
import requests
import bs4
flag = True
while flag:
URL = 'http://api.66daili.cn/API/GetCommonProxy/?orderid=2291244402101903832&num=20&token=66daili&format=text&line_separator=win&protocol=http&anonymous=elite,anonymous,transparent&area=%E4%B8%AD%E5%9B%BD&proxytype=https&speed=fast#api'
ip_list = check_ip(URL) #检查代理ip 能用的则把IP 装为一个列表
print(ip_list)
for i in range(len(ip_list)):
douban_url = 'https://movie.douban.com/top250'
headers = {
'User-Agent': 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36'
}
# 代理IP
proxy = {
'http': 'http://' + ip_list[i],
'https': 'https://' + ip_list[i]
}
try:
resp = requests.get(url=douban_url, headers=headers, proxies=proxy, timeout=1)
if resp.status_code == 200:
print(resp.text)
flag = False
break
except:
print('ERROR')