一、常见的Python爬虫库
Requests:处理Http请求。
lxml:HTML和XML文件解。
BeautifulSoup:网络抓取框架,用于解析和提取HTML和XML数据,通常用于小数据量的处理,不支持异步操作,通常搭配lxml使用。
Scrapy:比较强大的爬虫框架,适用于复杂大型任务的爬取。
Selenium:模拟用户访问浏览器操作,适合处理JS渲染的网页。
re:正则表达式。
二、爬虫示例 1
示例描述: 爬取自己的csdn博客,统计每篇博客的访问量,制作一个柱状图,以访问量从大到小的方式显示。
1. 从“个人主页”爬取所有所有文章的链接
1.1 查看爬取规则
打开个人主页,右键->检查:可以看到每篇文章的链接挂在哪个标签的哪个属性下( <article>标签下的<a>标签中的href属性值即为每篇文章的链接 )
1.2 提取网页中的所有文章ip
from bs4 import BeautifulSoup #pip3 install beautifulsoup4
from urllib.request import urlopen
homePage_url="https://blog.csdn.net/beautiful77moon?type=blog" #你的csdn个人主页链接
homePage_html=urlopen(homePage_url).read().decode('utf-8')
soup=BeautifulSoup(homePage_html,features='lxml')
#1.查找所有的<article>标签
li_articles=soup.find_all('article')
#2.取出所有<article>标签下<a>中的href属性值
article_urls=[]
for item in li_articles:
link=item.find_all('a')
article_urls.append(link[0]['href'])
print(link[0]['href'])
当页面内容过多时,需要下拉"加载",才能显示所有内容,所以需要一个工具模拟浏览器行为,自动滚动页面以加载更多内容。urllib无法处理这种情况,所以一般不建议使用 urllib。
1.3 使用selenium模拟浏览器。
1.3.1 下载浏览器驱动(以Edge为例)
查看自己的浏览器版本(点击浏览器右上角的三个点->设置->关于 Microsoft Edge)
下载对应版本的驱动:Microsoft Edge WebDriver | Microsoft Edge Developer
解压到一个目录下(这个目录后续会用到)
1.3.2 下载关键的依赖包
浏览器模拟器selenium:pip install selenium --index-url https://pypi.tuna.tsinghua.edu.cn/simple
处理网页的beautifulsoup:pip install beautifulsoup4 --index-url https://pypi.tuna.tsinghua.edu.cn/simple
1.3.3 代码
模拟浏览器,实现“滑动鼠标”下拉页面以加载更多数据的行为
从个人主页提取所有文章的url并打印
from selenium import webdriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.edge.options import Options
from bs4 import BeautifulSoup
import time
# 设置 Edge驱动 的路径
edge_driver_path = 'E:\SoftWare_work\download\edgedriver_win64\msedgedriver.exe' # 替换为你本地的 EdgeDriver 路径
# 配置 Edge浏览器选项
edge_options = Options()
edge_options.add_argument("--headless") # # 无头模式。不可视化浏览器页面。如果注释掉这行,每次运行代码都会打开浏览器页面。
# 启动浏览器
service = Service(edge_driver_path)
driver = webdriver.Chrome(service=service, options=edge_options)
# 打开网页
homePage_url = "https://blog.csdn.net/beautiful77moon?type=blog"
driver.get(homePage_url)
# 滚动页面以加载更多内容
# driver.execute_script("return window.pageYOffset + window.innerHeight") 用于获取当前视口底部相较于页面顶部位置的 JavaScript 代码
# window.pageYOffset:当前视口顶部相对于页面顶部的垂直滚动距离。表示页面的顶部已经滚动了多少像素 假设为1200px
# window.innerHeight:浏览器视口的高度(即当前显示区域的高度) 假设为800px
# last_height = window.pageYOffset + window.innerHeight = 2000px
last_height = driver.execute_script("return window.pageYOffset + window.innerHeight")
while True:
#driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") #使用 JavaScript 滚动到页面底部以加载更多数据
#模拟鼠标滚动
#第一个参数表示水平方向不滚动
#第二个参数表示垂直方向上滚动1000像素
driver.execute_script(f"window.scrollBy(0, 1000);")
time.sleep(5) #等待页面加载
new_height = driver.execute_script("return window.pageYOffset + window.innerHeight")#driver.execute_script("return document.body.scrollHeight") #获取当前页面的高度,检测是否已加载更多内容
if new_height == last_height:
break
last_height = new_height
# 获取页面源代码
page_source = driver.page_source
# 关闭浏览器
driver.quit()
# 解析页面内容
soup = BeautifulSoup(page_source, 'lxml')
# 查找所有的<article>标签
li_articles = soup.find_all('article')
# 取出所有<article>标签下<a>中的href属性值
article_urls = []
for item in li_articles:
links = item.find_all('a')
if links:
article_urls.append(links[0].get('href'))
print(links[0].get('href'))
print(len(article_urls)) #116
2. 统计每篇文章的访问量
2.1 查看爬取规则
参考 1.1
2.2 爬取数据
注意:1.3.3 代码中的 driver.quit() 需要注释掉,否则不能正常浏览其他网页,会报错
import re
#分析每篇文章的访问量,收藏量,点赞数
class Article_Detail:
def __init__(self,article_name="",read="",collect="",like=""):
self.article_name=article_name #文章名字
self.read=read #阅读量
self.collect=collect #收藏量
self.like=like #点赞量
articles_details=[]
for item in article_urls:
driver.get(item)
page_source=driver.page_source
#driver.quit()
soup = BeautifulSoup(page_source,'lxml')
# 阅读量、收藏量、点赞数所在标签过滤
bar_content=Article_Detail()
get_name=(soup.find('h1',attrs='title-article',id='articleContentId')).get_text()
get_read=(soup.find('span','read-count')).get_text(strip=True) #strip=True去除前后空格
get_collection=(soup.find('span','get-collection')).get_text(strip=True)
get_like=(soup.find('span',id='blog-digg-num')).get_text(strip=True)
#统计文章的阅读量、收藏量、点赞数
bar_content.article_name=get_name
match=re.search(r'\d+',get_read) #使用正则表达式匹配字符串中的一个或多个数字
bar_content.read= match.group() if match else 0
match = re.search(r'\d+', get_collection) # 使用正则表达式匹配字符串中的一个或多个数字
bar_content.collect = match.group() if match else 0
match = re.search(r'\d+', get_like) # 使用正则表达式匹配字符串中的一个或多个数字
bar_content.like = match.group() if match else 0
articles_details.append(bar_content)
for item in articles_details:
print(item.article_name+":阅读量["+item.read+"],收藏量["+item.collect+"],点赞数["+item.like+"]")
** 运行结果:**
三、爬虫框架Scrapy
使用Scrapy框架实现"示例1"中的功能,并将爬取的结果进行保存。
1. Scrapy框架与BeautifulSoup框架的区别:
Scrapy教程
[功能方面]
- Scrapy:- 数据类型:可以处理各种类型的数据。- 功能方面:包括请求管理、数据解析/提取、数据存储(JSON、CSV、XML)等。- 请求方式:使用异步 I/O,使其能够高效地处理大量请求。- 支持的特性:支持中间件、管道、爬虫调度等功能,适合大规模的抓取项目。- 自动处理:能够自动处理重定向、用户代理、更换IP等。
- **BeautifulSoup: ** - 数据类型:是一个用于解析 HTML 和 XML 的库,主要用于提取网页内容。- 功能方面:只解析和提取数据,不包括请求管理和数据存储。- 请求方式:同步I/O操作,通常与requests等库配合使用。
[性能方面]
- Scrapy:- 性能高:因其异步I/O和内置的请求调度功能,适合大规模抓取。- 扩展性强:可以通过中间件和扩展进行功能扩展,如处理JavaScript渲染内容等。
- BeautifulSoup:- 性能较低:通常用于小规模数据抓取,不支持异步操作。- 扩展性有限,主要集中与数据解析,需要与其他工具组合使用。
[适用场景]
- Scrapy:- 大规模爬取:适合需要高效处理大量数据的项目。- 复杂任务抓取:适用于抓取并处理多个页面、分页、异步请求等复杂任务。
- BeautifulSoup:- 小型抓取:适合简单的数据提取任务。- 数据解析:已经知道了html内容,只需要解析和提取数据时。
2. Scrapy框架使用步骤
命令行创建一个爬虫项目:scrapy startproject csdn_blog
进入项目目录:cd csdn_blog
创建爬虫(scrapy genspider+爬虫文件名+爬取网页网址):scrapy genspider csdn_spider https://blog.csdn.net/beautiful77moon?type=blog
打开items.py定义item容器
import scrapy
class CsdnBlogItem(scrapy.Item):
# define the fields for your item here like:
title=scrapy.Field()
read=scrapy.Field()
collect=scrapy.Field()
like=scrapy.Field()
- 进入 csdn_spider.py编写爬虫代码
import re
import scrapy
class CsdnSpiderSpider(scrapy.Spider):
name = "csdn_spider"
allowed_domains = ["blog.csdn.net"]
start_urls = ["https://blog.csdn.net/beautiful77moon?type=blog"]
def parse(self, response):
#提取文章链接
article_urls=response.css('article a::attr(href)').getall() # ::attr(href) 提取href属性的值
article_urls=[url for url in article_urls if url.startswith("https://")]
#分析所有链接
for url in article_urls:
yield scrapy.Request(url,callback=self.parse_article)
#提取每篇文章的数据
def parse_article(self,response):
title=response.css('h1.title-article::text').get(default='N/A').strip() #::text 提取文本内容
read=self.extract_number(response.css('span.read-count::text').get(default='0').strip()) #
collect=self.extract_number(response.css('span.get-collection::text').get(default='0').strip()) # '.':class
like=self.extract_number(response.css('span#blog-digg-num::text').get(default='0').strip()) # '#':id
yield {
'title':title,
'read' : read,
'collect' : collect,
'like' : like
}
def extract_number(self,text):
match=re.search(r"\d+",text)
return match.group() if match else '0'
- 运行: scrapy crawl csdn_spider -o articles.json (将爬取的内容输出到articles.json)
注意: 运行时会报错:Forbidden by robots.txt: <GET https://blog.csdn.net/beautiful77moon?type=blog>
网站的robots.txt文件阻止了 Scrapy 访问该页面,可以修改settings.py中的ROBOTSTXT_OBEY = False配置:来忽略robots.txt规则。(谨慎使用)
7. 运行结果如下:
四、使用Jupyter对结果进行可视化
未完结
版权归原作者 赵 XiaoQin 所有, 如有侵权,请联系我们删除。