Python自学笔记——多线程微信文章爬取

本文介绍了一个使用Python实现的多线程爬虫案例,该爬虫能够从搜狗微信搜索抓取特定关键词的文章链接及内容。通过三个线程分别负责获取网址、抓取文章详情及监控程序状态,实现了高效稳定的数据抓取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

# -*- coding: utf-8 -*-

"""

Created on Tue Dec 26 10:34:09 2017

@author: Andrew

"""

#线程1专门获取对应网址并处理为真是网址,然后将网址写入队列urlqueue中,该队列专门用来存放具体文章的网址

#线程2与线程1并行,从线程1提供的网址中依次爬取对应文章信息并处理,处理后将我们需要的结果写入对应的本地文件中

#线程3主要用于判断程序是否完成。因为在此如果没有一个总体控制的线程,即使线程1、2执行完,也不会退出程序

#在正规的项目设计时,尽量并行执行的线程执行的时间相近

#建立合理的延时机制,如:发生异常或让执行较快的线程进行延时。

#建立合理的异常处理机制

导入所需的模块


import threading

import queue

import re

import urllib.request

import time

import urllib.error

#创建一个网址队列


urlqueue=queue.Queue()

#模拟成浏览器


headers=("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36")

opener=urllib.request.build_opener()

opener.add_handler=[headers]

#将opener安装为全局

urllib.request.install_opener(opener)

#建立空url列表


listurl=[]

#读取网页源代码


def readdata(url):

    try:

        data=urllib.request.urlopen(url).read().decode('utf-8')

        return data

    except urllib.error.URLError as e:

        if hasattr(e,"code"):

            print(e.code)

        if hasattr(e,"reason"):

            print(e.reason)

        time.sleep(10)

    except Exception as e:

        print("exception:"+str(e))

        time.sleep(1)

#线程1,专门获取对应网址并处理为真实网址


class geturl(threading.Thread):

    def __init__(self,key,pagestart,pageend,urlqueue):

        threading.Thread.__init__(self)

        self.pagestart=pagestart

        self.pageend=pageend

        self.urlqueue=urlqueue

    def run(self):

        page=self.pagestart

        #编译关键词key

        keycode=urllib.request.quote(key)

        for page in range(self.pagestart,self.pageend+1):

            url="http://weixin.sogou.com/weixin?query="+keycode+"&_sug_type_=&sut=31049&lkt=0%2C0%2C0&s_from=input&_sug_=y&type=2&sst0=1514192636409&page="+str(page)+"&ie=utf8&w=01019900&dr=1"

            data1=readdata(url)

            #列表页url正则

            listurlpat='<div class="txt-box">.*?(http://.*?)"'

            listurl.append(re.compile(listurlpat,re.S).findall(data1))

            #便于调试

        print("获取到"+str(len(listurl))+"页")

        for i in range(0,len(listurl)):

            #等一等线程2,合理分配资源

            time.sleep(7)

            for j in range(0,len(listurl[i])):

                try:

                    url=listurl[i][j]

                    #处理成真实url,采集网址比真实网址多了一串"amp;"

                    url=url.replace("amp;","")

                    print("第"+str(i)+","str(j)+"次入队")

                    self.urlqueue.put(url)

                    self.urlqueue.task_done()                    

                except urllib.error.URLError as e:

                    if hasattr(e,"code"):

                        print(e.code)

                    if hasattr(e,"reason"):

                        print(e.reason)

                    #若为URLError异常,延时10秒执行

                    time.sleep(10)

                except Exception as e:

                    print("exception:"+str(e))

                    #若为Exception异常,延时1秒执行

                    time.sleep(1)

 

#线程2,与线程1并行,从线程1提供的网址urlqueue中依次爬去对应文章信息并处理


class getcontent(threading.Thread):

    def __init__(self,urlqueue):

        threading.Thread.__init__(self)

        self.urlqueue=urlqueue

    def run(self):

        html='''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

            <html xmlns="http://www.w3.org/1999/xhtml">

            <head>

            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

            <title>微信文章页面</title>

            </head>

            <body>'''

        fh=open("C:/Python35/3.html","wb")

        fh.write(html.encode("utf-8"))

        fh.close()

        fh=open("C:/Python35/3.html","ab")

        i=1

        while(True):

            try:

                url=self.urlqueue.get()

                data=readdata(url)

                #文章标题正则表达式

                titlepat="<title>(.*?)</title>"

                #文章内容正则表达式

                contentpat='id="js_content">(.*?)id="js_sg_bar"'

                #通过对应正则表达式找到标题并赋给列表title

                title=re.compile(titlepat).findall(data)

                #通过对应正则表达式找到内容并赋给content

                content=re.compile(contentpat,re.S).findall(data)

                #初始化标题与内容

                thistitle="此次没有获取到"

                thiscontent="此次没有获取到"

                #如果标题列表不为空,说明找到了标题,去列表第0个元素,即次标题赋给thistitle

                if(title!=[]):

                    thistitle=title[0]

                if(thiscontent!=[]):

                    thiscontent=content[0]

                #将标题与内容汇总赋给变量dataall

                dataall="<p>标题为:"+thistitle+"</p><p>内容为:"+thiscontent+"</p><br>"

                #将该篇文章的标题与内容的总信息写入对应文件

                fh.write(dataall.encode("utf-8"))

                print("第"+str(i)+"个网页")#便于调试

                i+=1

            except urllib.error.URLError as e:

                    if hasattr(e,"code"):

                        print(e.code)

                    if hasattr(e,"reason"):

                        print(e.reason)

                    #若为URLError异常,延时10秒执行

                    time.sleep(10)

            except Exception as e:

                    print("exception:"+str(e))

                    #若为Exception异常,延时1秒执行

                    time.sleep(1)

        fh.close()

        html4='''</body>

        </html>

        '''

        fh=open("C:/Python35/3.html","ab")

        fh.write(html4.encode("utf-8"))

        fh.close()

#并行控制程序,若60秒未响应,并且url的队列已空,则判断为执行成功


class contrl(threading.Thread):

    def __init__(self,urlqueue):

        threading.Thread.__init__(self)

        self.urlqueue=urlqueue

    def run(self):

        while(True):

            print("程序执行中")

            time.sleep(60)

            if(self.urlqueue.empty()):

                print("程序执行完毕!")

                exit()

#运行


key="考研数学泄题"

pagestart=1#起始页

pageend=2#爬取到哪页

#创建线程1对象,随后启动线程1

t1=geturl(key,pagestart,pageend,urlqueue)

t1.start()

#创建线程2对象,随后启动线程2

t2=getcontent(urlqueue)

t2.start()

#创建线程3对象,随后启动线程3

t3=contrl(urlqueue)

t3.start()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值