我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python进阶多线程爬取网页项目实战

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python进阶多线程爬取网页项目实战

上一篇文章介绍了并发和多线程的概念,这次就来向大家上一个实战来讲解一下如何真正的运用上多线程这个概念。
有需要的可以看看我之前这篇文章:Python进阶篇之多线程爬取网页

一、网页分析

这次我们选择爬取的网站是水木社区的Python页面
网页:https://www.mysmth.net/nForum/#!board/Python?p=1

在这里插入图片描述

根据惯例,我们第一步还是分析一下页面结构和翻页时的请求。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

通过前三页的链接分析后得知,每一页链接中最后的参数是页数,我们修改它即可得到其他页面的数据。

再来分析一下,我们需要获取帖子的链接就在id 为 body 的 section下,然后一层一层找到里面的 table,我们就能遍历这些链接的标题。

在这里插入图片描述

我们点开一篇帖子:https://www.mysmth.net/nForum/#!article/Python/162717

和前面一样,我们先分析标题和内容在网页中的结构

不难发现,主题部分只要找到 id 为 main 的 section 下面的 class 为 b-head corner 的下面第二个 span即可
主题部分

在这里插入图片描述

而内容部分只要找到class 为 a-wrap corner 的 div,找到下面的 a-content即可。
内容部分

在这里插入图片描述

分析网页结构后,我们就可以开始写代码了!

二、代码实现

首先要确定要保存什么内容:这次我们保存水木社区 Python 版面前 10 页的所有帖子标题和帖子第一页的所有回复。

解析列表页,得到所有的帖子链接


from bs4 import BeautifulSoup
# 解析列表页内容,得到这一页的内容链接
def parse_list_page(text):
  soup = BeautifulSoup(text, 'html.parser')
	# 下面相当于 soup.find('table', class_='board-list tiz').find('tbody')
  tbody = soup.find('table', class_='board-list tiz').tbody
  urls = []
  for tr in tbody:
    td = tr.find('td', class_='title_9')
    urls.append(td.a.attrs['href'])
  return urls

解析内容页,得到标题和这一页的所有帖子内容


# 解析内容页,得到标题和所有帖子内容
def parse_content_page(text):
  soup = BeautifulSoup(text, 'html.parser')
  title = soup.find('span', class_='n-left').text.strip('文章主题:').strip()
  content_div = soup.find('div', class_='b-content corner')
  contents = []
  for awrap in content_div.find_all('div', class_='a-wrap corner'):
    content = awrap.p.text
    contents.append(content)
  return title, contents

把列表页的链接转换成我们要抓取的链接


def convert_content_url(path):
  URL_PREFIX = 'http://www.mysmth.net'
  path += '?ajax'
  return URL_PREFIX + path

生成前 10 页的列表页链接


list_urls = []
for i in range(1, 11):
  url = 'http://www.mysmth.net/nForum/board/Python?ajax&p='
  url += str(i)
  list_urls.append(url)

下面是得到前 10 页列表页里所有正文的链接。这个时候我们使用线程池的方式来运行


import requests
from concurrent import futures
session = requests.Session()
executor = futures.ThreadPoolExecutor(max_workers=5)
# 这个函数获取列表页数据,解析出链接,并转换成真实链接
def get_content_urls(list_url):
  res = session.get(list_url)
  content_urls = parse_list_page(res.text)
  real_content_urls = []
  for url in content_urls:
    url = convert_content_url(url)
    real_content_urls.append(url)
  return real_content_urls
# 根据刚刚生成的十个列表页链接,开始提交任务
fs = []
for list_url in list_urls:
  fs.append(executor.submit(get_content_urls, list_url))
futures.wait(fs)
content_urls = set()
for f in fs:
  for url in f.result():
    content_urls.add(url)

在这里要注意一下,第 23 行中我们使用了 set() 函数,作用是去除重复值。它的原理是创建一个 Set(集合),集合 是 Python 中的一种特殊数据类型,其中可以包含多个元素,但是不能重复。我们来看看 set() 的用法


numbers = [1, 1, 2, 2, 2, 3, 4]
unique = set(numbers)
print(type(unique))
# 输出:<class 'set'>
print(unique)
# 输出:{1, 2, 3, 4}

我们看到,set() 将列表 numbers 转换成了没有重复元素的集合 {1, 2, 3, 4}。

我们利用这个特性,首先在 23 行通过 content_urls = set() 创建了一个空集合,之后在其中添加链接时,就会自动去除多次出现的链接。

得到了所有正文链接之后,我们解析正文页内容,放到一个字典里


# 获取正文页内容,解析出标题和帖子
def get_content(url):
  r = session.get(url)
  title, contents = parse_content_page(r.text)
  return title, contents
# 提交解析正文的任务
fs = []
for url in content_urls:
  fs.append(executor.submit(get_content, url))
futures.wait(fs)
results = {}
for f in fs:
  title, contents = f.result()
  results[title] = contents
print(results.keys())

就这样,我们完成了多线程的水木社区爬虫。打印 results.keys() 可以看到所有帖子的标题。

这次爬取了前十页的所有主题,以及他们的第一页回复。一共 10 个列表页、300 个主题页,解析出 1533 条回复。在一台网络良好、性能普通的机器上测试执行只花费了 13 秒左右。

完整代码如下


import requests
from concurrent import futures
from bs4 import BeautifulSoup
# 解析列表页内容,得到这一页的内容链接
def parse_list_page(text):
  soup = BeautifulSoup(text, 'html.parser')
  tbody = soup.find('table', class_='board-list tiz').tbody
  urls = []
  for tr in tbody:
    td = tr.find('td', class_='title_9')
    urls.append(td.a.attrs['href'])
  return urls
# 解析内容页,得到标题和所有帖子内容
def parse_content_page(text):
  soup = BeautifulSoup(text, 'html.parser')
  title = soup.find('span', class_='n-left').text.strip('文章主题:').strip()
  content_div = soup.find('div', class_='b-content corner')
  contents = []
  for awrap in content_div.find_all('div', class_='a-wrap corner'):
    content = awrap.p.text
    contents.append(content)
  return title, contents
# 把列表页得到的链接转换成我们要抓取的链接
def convert_content_url(path):
  URL_PREFIX = 'http://www.mysmth.net'
  path += '?ajax'
  return URL_PREFIX + path
# 生成前十页的链接
list_urls = []
for i in range(1, 11):
  url = 'http://www.mysmth.net/nForum/board/Python?ajax&p='
  url += str(i)
  list_urls.append(url)
session = requests.Session()
executor = futures.ThreadPoolExecutor(max_workers=5)
# 这个函数获取列表页数据,解析出链接,并转换成真实链接
def get_content_urls(list_url):
  res = session.get(list_url)
  content_urls = parse_list_page(res.text)
  real_content_urls = []
  for url in content_urls:
    url = convert_content_url(url)
    real_content_urls.append(url)
  return real_content_urls
# 根据刚刚生成的十个列表页链接,开始提交任务
fs = []
for list_url in list_urls:
  fs.append(executor.submit(get_content_urls, list_url))
futures.wait(fs)
content_urls = set()
for f in fs:
  for url in f.result():
    content_urls.add(url)
# 获取正文页内容,解析出标题和帖子
def get_content(url):
  r = session.get(url)
  title, contents = parse_content_page(r.text)
  return title, contents
# 提交解析正文的任务
fs = []
for url in content_urls:
  fs.append(executor.submit(get_content, url))
futures.wait(fs)
results = {}
for f in fs:
  title, contents = f.result()
  results[title] = contents
print(results.keys())

本次分享到此结束,谢谢大家阅读!!
有问题欢迎评论区留言!!

更多关于Python多线程爬取网页实战的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python进阶多线程爬取网页项目实战

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python实战项目:爬取某网帅哥图片

前言我也不知道说啥了, 看呗,就当是一个案例练习吧,首先导入库from bs4 import BeautifulSoupfrom urllib.request import urlretrieveimport requestsimport
2023-06-02

Python项目实战:爬取网易云音乐评论

前言相信大家都非常喜欢听音乐的吧,每一首歌背后都有一个故事,有爱情,有离别,有仇恨,有不舍等等,听着自己喜欢总会唏嘘,我不仅喜欢听歌,还喜欢看歌曲下面的评论,很多人都阐述了自己对歌曲的看法和理解,除了一些,你懂的..、废话不多说了。上代码吧
2023-06-02

Python项目实战:使用多线程进行TCP端口扫描

前言今天为大家一个利用Python扫描开放主机的TCP端口,首先你要查看其中的开放的端口,创建一个TCP全连接扫描器,一般使用socket来创建连接器的,测试当前主机和端口是否开放,直接使用socket连接导入第三方库
2023-06-02

Python 网络编程项目实战:打造在线游戏

,从搭建服务端和客户端,到实现玩家注册、登录、游戏对战等功能,一步步带你领略 Python 网络编程的魅力。
Python 网络编程项目实战:打造在线游戏
2024-02-13

Python 网络编程项目实战:打造多人聊天室

本文将带领读者使用 Python 语言构建一个多人聊天室项目,演示如何使用套接字编程和多线程处理来实现多人同时在线聊天。
Python 网络编程项目实战:打造多人聊天室
2024-02-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录