返回介绍

第 13 章 Python 并发编程

发布于 2025-04-20 18:52:17 字数 2427 浏览 0 评论 0 收藏

现在拥有多核 CPU 的服务器随处可见,充分利用语言特性,使用并发方式编程也是 Web 开发者一项必须掌握的日常技能。好的并发程序远比单线程单进程的程序的运行效率高得多。本章我们通过抓取微信公众号文章内容并存入 MongoDB 数据库,来演示 Python 的并发技术。

编写爬虫(Crawler)程序算是不同级别 Python 工程师都可能涉及的工作之一,所谓爬虫就是让程序自动访问目标网站,解析页面,把需要的内容保存下来。写好爬虫其实原则只有一条,就是让你的抓取行为和用户访问网站的真实行为尽量一致。举些例子,用户不会 1 秒钟打开 10 个页面,也不会使用不符合浏览器格式的用户代理(User-Agent,UA),有些页面的 Referfer 和浏览器 Cookie 也很重要。为了保证爬虫持续稳定,甚至于还要模拟用户的正常行为,如发帖、签到、给别人点赞、参与讨论等。这些细节做好了,基本上什么网站都可以抓取成功。

为了让抓取顺利,我们要做好如下 4 件事:

1.使用代理。一般的网站都有一些防爬虫的策略,如限制单位时间内页面的请求次数,基于来源 IP、UA 等请求信息判断用户访问是否正常。单机抓取整个网站内容,要想快速完成显然是不可能的,那么就需要分布式地使用多个服务器来抓取。如果公司没有专门的抓取服务器,可以从网上找一些代理服务器来使用。

2.伪造 UA 字符串。每次请求都使用随机生成的 UA。

3.选择解析 HTML 的方式。BeautifulSoup 是一个可以从 HTML 或 XML 文件中提取数据的 Python 库。我们还需要给它配置一个解析器,解析器提供了相同的、非常人性化的接口,使用非常简便。常见的解析器包含如下几种:

  • html.parser。使用 Python 标准库自带的解析器,文档容错能力强,但是速度上没有优势。
  • lxml。lxml 是一个 C 语言实现的 libxml2 和 libxslt 的 Python 绑定库,速度比其他的选择快得多,而且文档容错能力强。
  • html5lib。容错性最好,它的解析方式和其他解析器相比有所不同,它会以浏览器的方式解析文档。

4.使用 Referfer。使用 Referfer 是一个好习惯,模仿一个从搜索引擎点击进来的请求,更不容易被封禁。

由于 BeautifulSoup 的易用性和 lxml 效率,笔者选择两者的组合来实现页面的解析。先安装它们。

> pip install beautifulsoup4 lxml

需要抓取的内容分三种:

  • 抓取多个代理网站上发布的代理地址,把解析的代理地址存进数据库备用。将使用多线程完成。
  • 抓取微信工作平台的搜索列表页。我们使用搜狗的微信搜索平台(http://weixin.sogou. com )。搜索支持两种类型,分别是微信公众号和和微信文章,本章将抓取包含 Python 关键词的文章,也就是使用 type=2。将使用协程完成。
  • 抓取微信文章内容,微信文章的域名是 http://mp.weixin.qq.com。将分别使用多进程、Future 和 aysncio 三种方式完成。

为了减少复杂度,随机生成 UA 的功能通过第三方库 fake-useragent 实现:

> pip install fake-useragent

生成一个 UA 字符串只需要如下代码即可:

In : from fake_useragent import UserAgent
In : ua=UserAgent()
In : ua.random
Out: u'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome
     /41.0.2228.0 Safari/537.36'
In : ua.random
Out: u'Mozilla/5.0 (Macintosh;Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like
     Gecko) Chrome/35.0.1916.47 Safari/537.36'

我们使用 MongoEngine 管理数据模型。先定义基类:

from mongoengine import connect, StringField, DateTimeField, Document
 
from config import DB_HOST, DB_PORT, DATABASE_NAME
 
connect(DATABASE_NAME, host=DB_HOST, port=DB_PORT)
 
class BaseModel(Document):
    create_at=DateTimeField()
 
    meta={'allow_inheritance':True,
          'abstract':True}
 
BaseModel 的 meta 属性将允许其被继承。
 
config.py 存放配置常量:
 
DB_HOST='localhost'
DB_PORT=27017
DATABASE_NAME='chapter13'

为了让例子更简单易懂,本章的例子都使用过程式编程。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。