- 网页爬取
- 访问网页
- requests
- selenium
- 解析网页
- lxml
- BeautifulSoup
- 动态网页的爬取
- requests
- selenium
- 图片的爬取
这是一篇自己写的关于爬虫学习过程的笔记。
访问网页 requests使用requests库主要是用于爬取静态网页,爬取到的源代码仅网页源代码,对于大多数网页而言,即是网页的框架,不包含我们所能在网页上看到的图片、数据等。
import requests
url = 'http://…….com/' # url为所要爬取的网页网址,以下所有url均隐藏
respond = requests.get(url) # 请求访问网络
respond.status_code # 状态的编码
respond.text # 响应,获取网页源代码(HTML)
respond.content # 网页源代码,bytes类型
respond.encoding # 可改变读取网页的编码格式
headers = {'user_agent':'Mozilla/5.0 (Windows ……(省略)} # 在开发者工具出可以找到访问所使用的一系列header
respond2 = requests.get(url, headers=headers, timeout=2.) # 改变hearders,使得访问更像真实浏览器;超过2秒不再访问
除了get方法,还有别的方法向网页发送请求,可以在开发者工具中查找当前网页的请求方法。
seleniumanaconda的python环境中并没有安装到selenium的库,有其他博文专门写了专门安装库,及其插件,在此处就不赘述了,自行查找资料安装。
此处打开的是微软Microsoft Edge浏览器。
from selenium import webdriver driver = webdriver.Edge() # 打开浏览器 driver.get(url) # 打开网页 driver.page_source # 获取当前动态网页源码,所视数据均被下载,与requests不同解析网页
解析网页主要有两个方法,lxml 的 etree,和 bs4 的 BeautifulSoup。
然后是定位获取目标元素的方法 xpath 和 select ,
对于xpath和select的索引位置获取,在开发者工具,对想要获取的数据右键,就可以迅速获取:
lxml在索引时常使用的是xpath。
from lxml import etree
doc = etree.HTML(html)
# 解析网页,此处解析网页所使用的文本可以是respond.text 也可以是driver.page_source,或者是导入的源码文件
doc.xpath('/html/body/p/b/text()') # 通过绝对路径定位目标元素,加text可直接查看文本
doc.xpath('//b/text()') # 相对路径,获取b下的文本信息
doc.xpath('//p/a/@href') # 通过@可以获取目标元素属性值
BeautifulSoup
BeautifulSoup也可以使用 lxml 的解析方法,在索引的时候通常使用select而不是xpath。
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'lxml') # 在 BeautifulSoup也可以使用 lxml 的解析方法
soup.select('html > body > p > b') # 绝对路径
soup.select('p > b') # 可以不从最顶级标签写起
soup.select('body a') # 相对路径不需要 > ,取出body下的所有a
soup.select('p:nth-of-type(2)') # 取出第二个p标签
soup.select('p > a[id="link1"]') # 添加具体属性索引不需要加@
souped[0].get('href') # 获取目标元素属性值,使用 get 函数
动态网页的爬取
requests
动态网页更多可能使用selenium进行获取信息,但是requests也是可以使用的,此时需要先进行逆向分析获得网页网址。
获取到了所需要爬取的数据的网址(记住不是网页网址),再调用get函数访问网站。此时就可以获取到数据的源码。往往获取到的源码是一个json格式的文本,使用json库转换可以直接得到一个字典,但是也要注意查看,这个源码的文本是不是完全符合字典格式,否则转换时会报错。
url_detect = 'https://www.……com.cn/……' # 获取到的url respond_detect = requests.get(url_detect) respond_detect.text import json json.loads(respond_detect.text) # loads将字符串转为json格式,该字符串的形式可以直接解析成一个列表
若第一个字符不是花括号,要先对字符串进行处理。
from selenium import webdriver
from bs4 import BeautifulSoup
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
import time
url = 'https://www.ptpress.com.cn'
driver = webdriver.Edge() # 打开浏览器
driver.get(url) # 打开网页
wait = WebDriverWait(driver, 10) # 设置等待时长
/confirm/i_btn = wait.until(
EC.element_to_be_clickable(
(By.CSS_SELECtOR, '#newBook > div.main > div.tabs > span:nth-child(2)')
# 定位要点击的按钮位置
)
)
/confirm/i_btn.click() # 执行点击操作
time.sleep(2) # 暂停一会,等待浏览器响应,再获取对应网页数据
soup = BeautifulSoup(driver.page_source, 'lxml') # 对点击后的网页获取源码 并 解析
souped = soup.select('#newBook > div.main > div.list > div > div > a > p') # 取出目标信息
在这里要注意的是,点击之后并不能一下子就获取到新网页的数据,这是因为网页的访问在执行下一条解析程序前还没完成响应,因此会获取到原网页的数据,此时可以使用time.sleep()让程序短暂休眠,以等待网站响应。
import time time.sleep(2) # 在点击操作后使用
对于想获得子网页的数据,此时使用selenium就不合适了,selenium 点击后获取的是被点击网页的数据,而不能获取打开的新标签页的数据。这种情况可以使用requests ,逆向分析在源码中找到子网页的网址(即获取目标元素属性值),依次 get 访问再爬取数据。
图片的爬取第一步:获取网页,发送请求
#1.发送HTTP请求
url = 'http://www/…….com/weimei/index.htm' # 某个图片网站
respond = requests.get(url)
respond.encoding = 'gbk' # 更改获取网页的编码方式
# 在开发者工具的在console控制台输入document.charset 然后回车可查得网页编码方式
html = respond.text
第二步,获取图片链接 及 图片名称(用于保存图片时命名使用)
#2.网页解析
dom = BeautifulSoup(html) # document object model
#获取网页壁纸链接
# 法一:select 获取
res = dom.select('#main > div.list > ul > li > a > img') # 获取全部图片
[i.get('src') for i in res] # src为img的一个属性,存放了图片的网址
# 法二:xpath 获取
from lxml import etree
dom = etree.HTML(html, etree.HTMLParser())
pic_http = dom.xpath('//*[@id="main"]/div[3]/ul/li/a/img/@src')
# 法三:正则表达式
import re
re.findall('([^<>]{2,})', html) # 法二:中文可以用非…字符表示,用中括号即对提取的任意字符添加限制条件
第三步:将图片保存到本地
#3.数据保存
# 下载壁纸,并保存到指定路径
url0 = pic_url[0]
# 1 发送请求,获取图片信息,返回python内存空间rl
rq2 = requests.get(url0)
# 2 将内存空间的信息以图片的形式保存到本地
with open('./04-Python网络爬虫-实战/data/text.jpg', 'wb') as f:
f.write(rq2.content)
#多张图片保存
for url0, title0 in zip(pic_url, pic_names):
rq = requests.get(pic_url)
with open('./04-Python网络爬虫-实战/data/{}.jpg'.format(pic_names), 'wb') as f:
f.write(rq.content) # 以二进制的形式写入文件
下面封装了三个函数直接爬取:
import requests
from bs4 import BeautifulSoup
import pandas as pd
import os
import re
from lxml import etree
import time
def picture_download(pic_url, pic_title, pic_save_path='./04-Python网络爬虫-实战/data/picture'):
'''获取并保存图片'''
rq = requests.get(pic_url) # 访问图片的url
with open(pic_save_path + '/{}.jpg'.format(pic_title), 'wb') as f:
f.write(rq.content) # 以获取到的图片标题命名文件,保存图片
def get_picture(host_url, encoding='gbk'):
'''获取同一网页,所有图片的信息'''
rq = requests.get(host_url) #访问图片网站
rq.encoding = encoding # 更改请求的gbk
html = rq.text # 获取网页源码
dom = etree.HTML(html, etree.HTMLParser()) #解析网页
pic_url = dom.xpath('//*[@id="main"]//li/a/img/@src') # 获取图片网址
pic_titl = dom.xpath('//*[@id="main"]//li/a/b/text()') # 获取图片标题
for url0, title0 in zip(pic_url, pic_titl): # 对网址和标题整合,同时传入函数
picture_download(url0, title0)
def main():
'''循环获取多个网页的图片'''
for i in range(1,66):
print(f'正在获取第{i}页的壁纸'.center(50, '=')) # 宽度为50,居中,=填充
if i == 1: #网页第一页和第二页以后的网址格式不完全相同
url = 'http://www.…….com/weimei/index.htm'
else:
url = 'http://www.…….com/weimei/index_{}.htm'.format(i)
get_picture(url)
time.sleep(2)
print('爬虫结束')



