python3+sqlite3+多线程爬取某网站文章

  • 之前有爬取过某网站内容,抓取该网站发表的文章内容并保存到数据库,最近又想学一些爬虫方面的知识,所以把之前写的内容翻出来写一写笔记。
  • 首先使用谷歌浏览器分析网页源码,因为该网站是并没有涉及什么js、css渲染等动态网页,所以爬取的过程相对简单。
  • 爬取了该网站的标题、作者、发表时间、评论数、第一张大图的url和内容,然后格式化数据并保存到sqlite3
  • 其过程的实现很简单,就是简单的URL抓包提取网页,然后使用了正则表达式来提取数据,然后进行一些错误的判断和改进,并没有使用到太高级的爬虫技巧,还在继续学习之中。

  • 源码如下:

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

import urllib.request
import re
import sqlite3
import time
import random
import threading
import urllib.error
import sys
import socket
import io
from datetime import datetime


class Article(object):
    def __init__(self):
        self.url="http://wallstreetcn.com/"
        self.removeP=re.compile('</p>')#用来提取正文内容
        self.removeRight=re.compile('class=".*?"|align=".*?"|>')
        self.removeStrong=re.compile("<strong>|</strong>")
        self.removeAddr=re.compile('<a.*?>|</a>')
        self.replaceBR=re.compile('<br><br>|<br>|</br>')
        self.removeImg=re.compile('<img.*?>| {1,7}|&.*?;')
        self.removeExtraTag=re.compile('<.*?>|style=".*?"|value=".*?"')
        self.removeNoneLine=re.compile('\\n+')

    def get_content(self,article):
        #使用正则表达式匹配出标题、作者、日期、内容、第一张大图的url、评论数
        title = re.findall(r'<h1 class="article-title">(.*?)</h1>',article,re.S)
        author=re.search(r'<span class="item author">(.*?)target="_blank">(.*?)</a>(.*?)</span>',article,re.S)
        post_at=re.findall(r'<span class="item time">(.*?)</span>',article,re.S)
        time=post_at[0]
        year=time[:4]
        month=time[5:7]
        day=time[8:10]
        hour=time[12:]#对有中文时间格式处理,返回值为datetime格式

        p_content=re.findall(r'<p(.*?)</p>',article,re.S)#正文内容有多种类型,分别匹配
        span_content=re.findall(r'<span>(.*?)</span>',article,re.S)
        if p_content==None:
            content=span_content
        else:
            content=p_content

        str_data=''.join(content[:-4])
        removed_p=re.sub(self.removeP,'\\n',str_data)
        removed_strong=re.sub(self.removeStrong,'',removed_p)
        removed_addr=re.sub(self.removeAddr,'',removed_strong)
        removed_br=re.sub(self.replaceBR,'\\n',removed_addr)
        removed_img=re.sub(self.removeImg,'',removed_br)
        removed_tag=re.sub(self.removeExtraTag,'',removed_img)
        removed_right=re.sub(self.removeRight,'',removed_tag)
        content=re.sub(self.removeNoneLine,'\\n',removed_right)


        img_1=re.search(r'<img alt="(.*?)" src="(.*?!article\\.foil)" (.*?)',article,re.M|re.I)#处理文章第一张大图片的url
        img_2=re.search(r'<img src="(.*?!article\\.foil)" alt="(.*?)" (.*?)',article,re.M|re.I)
        if img_1!=None :
            img=img_1.group(2)
        elif img_2!=None:
            img=img_2.group(1)
        else:
            img=None

        comment_count=re.findall(r'<span class="wscn-cm-counter">(.*?)</span>',article,re.S)
        
        try:

            if img==None and comment_count==None:#有可能文章没有图片和评论,考虑以下几种情况
                return str(title[0]),str(author.group(2)),datetime.strptime(year+'-'+month+'-'+day+' '+hour,'%Y-%m-%d %H:%M:%S'),''.join(content),None,0
            elif img!=None and comment_count==None:
                return str(title[0]),str(author.group(2)),datetime.strptime(year+'-'+month+'-'+day+' '+hour,'%Y-%m-%d %H:%M:%S'),''.join(content),str(img),0
            elif img==None and comment_count!=None:
                return str(title[0]),str(author.group(2)),datetime.strptime(year+'-'+month+'-'+day+' '+hour,'%Y-%m-%d %H:%M:%S'),''.join(content),None,int(comment_count[0])
            else:
                return str(title[0]),str(author.group(2)),datetime.strptime(year+'-'+month+'-'+day+' '+hour,'%Y-%m-%d %H:%M:%S'),''.join(content),str(img),int(comment_count[0])
        except Exception as e:
            pass

    def create_table(self):
        conn=sqlite3.connect('article.db')
        #如果不存在一个art表,新建一个art表
        conn.execute("CREATE TABLE IF NOT EXISTS art(title varchar(80) PRIMARY KEY not null, author varchar(10),post_at TEXT not null,content varchar(255) not null,img varchar(20) ,comment_count integer);")
        conn.close()

    def save_content(self,title,author,post_at,content,img,comment_count):
        #连接并保存到数据库
        conn=sqlite3.connect('article.db')
        conn.execute("INSERT INTO art (title,author,post_at,content,img,comment_count)values(?,?,?,?,?,?)",(title,author,post_at,content,img,comment_count))
        result=conn.execute("SELECT * FROM art")
        return list(result)
        conn.close()

    def spider(self):
        cou=1
        for i in random.sample(range(19,247271),10000):#随机生成url,数字可以任意
            try:
                try:
                    full_url=self.url+'node'+'/'+str(i)#URL格式
                    page = urllib.request.urlopen(full_url,timeout=5)#设置请求时间限制
                    pages= page.read().decode('utf-8','ignore')
                    lst=self.get_content(pages)
                    #self.save_content(lst[0],lst[1],lst[2],lst[3],lst[4],lst[5])#不打印出结果
                    print(self.save_content(lst[0],lst[1],lst[2],lst[3],lst[4],lst[5]))#打印出结果
                    print('Downloaded Successfully...\\n')
                    cou+=1
                    time.sleep(1)
                    if cou>300:#控制爬取300篇文章,可以自行调节文章数量,量力而为
                        sys.exit()
                    else:
                        continue
                except Exception as e:
                    pass
            except socket.error as e:
                pass
    
                
    def main(self):
        #多线程爬取
        my_thread = threading.Thread(target = self.spider)
        my_thread.start()
        my_thread.join()

    

if __name__ == '__main__':
    a=Article()#实例化
    a.create_table()
    a.main()







  • 到此,一个小小的spider就完成了,就可以实现文章的抓取和保存到数据库了,在dos下的显示如下所示。
  • 最后,由于是第一次写爬虫,不足之处肯定还有很多,欢迎来挑刺,洗耳恭听,一直在学习与进步当中,继续,共勉。

本文为作者原创,保留所有权,欢迎转载,转载请注明出处,标明作者。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 你爬了吗? 要玩大数据,没有数据怎么玩?这里推荐一些33款开源爬虫软件给大家。 爬虫,即网络爬虫,是一种自动获取网...
    Albert新荣阅读 2,187评论 0 8
  • 33款可用来抓数据的开源爬虫软件工具 要玩大数据,没有数据怎么玩?这里推荐一些33款开源爬虫软件给大家。 爬虫,即...
    visiontry阅读 7,088评论 1 99
  • 要玩大数据,没有数据怎么玩?这里推荐一些33款开源爬虫软件给大家。 爬虫,即网络爬虫,是一种自动获取网页内容的程序...
    评评分分阅读 7,835评论 2 121
  • “我这一身的毛病,除了脑袋不清醒是车祸留下的,其他的,都是月子没做好给祸害的”说这句话时,婆婆垂着头,眼神...
    MoMo的心情阅读 476评论 0 0