介绍requests+threading多线程爬虫,提取采用xpath 和正则两种,介绍线程锁

爬虫专业的都喜欢scrapy框架,但scrapy上手需要时间,对初学者不太适合。

本文介绍使用requets爬虫,为了利于演示学习,使用了xpath解析html和完全使用正则来提取两种方法,仅供参考。

import requests,json,random
import re,threading
from lxml import etree

lock=threading.Lock()

user_agent_list = [         "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" ,        "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",         "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",         "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",         "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",         "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",         "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",         "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",         "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",         "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",         "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",         "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",         "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",         "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",         "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",         "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",         "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",         "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
    ]
count=0

def fang_com(page_url):    ##列表页

    header={}

    header[‘User-Agent‘]=random.choice(user_agent_list)
    header.update({
        "Host":"esf.sz.fang.com",
        #"Cookie":"global_cookie=fb1g6d0w64d2cmu86sv4g9n3va0j137sk48; vh_newhouse=3_1491312022_2816%5B%3A%7C%40%7C%3A%5D833300ee3177d88529c7aa418942ece9; newhouse_user_guid=2F163DE7-8201-7FA9-2FB6-E507FE6F03B1; SoufunSessionID_Esf=3_1495389730_232; sf_source=; s=; showAdsh=1; hlist_xfadhq_SZ=0%7c2017%2f5%2f25+1%3a21%3a47%7c; city=sz; __utmt_t0=1; __utmt_t1=1; __utmt_t2=1; logGuid=a768dd46-b85b-47f4-a7a0-0a6596cab4cd; __utma=147393320.1111837171.1491290389.1495646208.1495650134.9; __utmb=147393320.12.10.1495650134; __utmc=147393320; __utmz=147393320.1495650134.9.4.utmcsr=esf.sz.fang.com|utmccn=(referral)|utmcmd=referral|utmcct=/; unique_cookie=U_cqyov4ut5vv1al8e2858qhzgt17j2z06mph*14"
        })
    while(1):                     ###这个主要是,fang.com会随机返回几个10054或者10053,如果连页面都没读取到,提取就是后话了,这网站没有封杀,即使使用单ip只会很少时候随机来几个10054 ,(‘Connection aborted.‘, error(10054, ‘‘))
        text=‘‘
        try:
            text=requests.get(page_url,headers=header,timeout=10).text
            #print text
        except Exception as e:
            print e
        if text!=‘‘:
            break

    se = etree.HTML(text)                                 ###########为了利于大家学习,这段演示xpath提取信息
    all_dl=se.xpath(‘//dl[@class="list rel"]‘)
    print len(all_dl)
    for dl in all_dl:
        title=dl.xpath(‘.//dd[@class="info rel floatr"]/p[@class="title"]/a/text()‘)[0]

        url=dl.xpath(‘.//dd[@class="info rel floatr"]/p[@class="title"]/a/@href‘)[0]
        url=‘http://esf.sz.fang.com‘+url

        info_list=dl.xpath(‘.//dd[@class="info rel floatr"]/p[@class="mt12"]/text()‘)
        #print json.dumps(info,ensure_ascii=False)    #py2显示汉字,py3可以直接print mt12
        info=‘‘
        for l in info_list:
            l2= re.findall(‘\S*‘,l)[0]          ###消除空白和换行
            #print m_str
            info+=l2+‘|‘

        time.sleep(1)
        total_price,price_squere,huxin,cankao_shoufu,shiyong_mianji,jianzhu_mianji,years,discription=get_detail(url)

        lock.acquire()                  ###这里叫锁,一是保证count计数准确,而是不会导致多个线程乱print,导致看不清楚。加锁的目的是别的线程不能运行这段代码了。但我之前看到有的人乱加锁,把消耗时间很长的代码加锁,那样导致多线程就基本个废物
        global count
        count+=1
        print time.strftime(‘%H:%M:%S‘,time.localtime(time.time())),‘    ‘,count
        print ‘列表页:‘
        print ‘ title: %s\n url: %s\n info: %s\n‘%(title,url,info)

        print ‘详情页:‘
        print ‘ total_price: %s\n price_squere: %s\n huxin: %s\n cankao_shoufu: %s\n shiyong_mianji: %s\n jianzhu_mianji: %s\n years: %s \n‘%(total_price,price_squere,huxin,cankao_shoufu,shiyong_mianji,jianzhu_mianji,years)
        print ‘**************************************************************‘
        lock.release()

def get_detail(url):    ###详情页

    header={‘User-Agent‘:random.choice(user_agent_list)}
    header.update({"Host":"esf.sz.fang.com"})

    while(1):
        content=‘‘
        try:
            content=requests.get(url,headers=header,timeout=10).content
        except Exception as  e:
            print e
            pass
        if content!=‘‘:
            break

    content=content.decode(‘gbk‘).encode(‘utf8‘)  ##查看网页源代码可看到是gbk编码,直接print的话,如果你在pycharm设置控制台是utf8编码,那么控制台的中文则会乱码,cmd是gbk的恰好可以显示。如果你在pycharm设置控制台是utf8编码,需要这样做
    #print content

    inforTxt=getlist0(re.findall(‘(<div class="inforTxt">[\s\S]*?)<ul class="tool">‘,content))       ###########为了利于大家学习,这段演示正则表达式提取信息,某些信息可能在有的房子界面没有,要做好判断
    #print inforTxt

    total_price=getlist0(re.findall(‘</span>价:<span class="red20b">(.*?)</span>‘,inforTxt))

    price_squere=getlist0(re.findall(‘class="black">万</span>\((\d+?)元[\s\S]*?<a id="agantesfxq_B02_03"‘,inforTxt))
    huxin=getlist0(re.findall(‘<dd class="gray6"><span class="gray6">户<span class="padl27"></span>型:</span>(.*?)</dd>‘,inforTxt))
    cankao_shoufu=getlist0(re.findall(‘参考首付:</span><span class="black floatl">(.*?万)</span> </dd>‘,inforTxt))
    shiyong_mianji=getlist0(re.findall(‘>使用面积:<span class="black ">(.*?)</span></dd>‘,inforTxt))
    shiyong_mianji=getlist0(re.findall(‘\d+‘,shiyong_mianji))
    jianzhu_mianji=getlist0(re.findall(‘建筑面积:<span class="black ">(.*?)</span></dd>‘,inforTxt))
    jianzhu_mianji=getlist0(re.findall(‘\d+‘,jianzhu_mianji))
    years=getlist0(re.findall(‘<span class="gray6">年<span class="padl27"></span>代:</span>(.*?)</dd>‘,inforTxt))

    discription=getlist0(re.findall(‘style="-moz-user-select: none;">([\s\S]*?)<div class="leftBox"‘,content))
    #print discription
    #print total_price,price_squere,huxin,cankao_shoufu,shiyong_mianji,jianzhu_mianji,years

    return total_price,price_squere,huxin,cankao_shoufu,shiyong_mianji,jianzhu_mianji,years,discription

#get_detail(‘http://esf.sz.fang.com/chushou/3_193928457.htm‘)
def getlist0(list):
    if list:
        return list[0]
    else:
        return ‘空‘

if __name__==‘__main__‘:
    ‘‘‘                                       ##这个是单线程,单线程爬很慢,3000个房子信息,一个5秒,那也得15000秒了,很耽误时间
    for i in range(1,101):
        page_url=‘http://esf.sz.fang.com/house/i3%s‘%i
        fang_com(page_url)
    ‘‘‘
    threads=[]                                            ###这个是演示多线程爬取
    for i in range(1,101):                                             #开了100线程,这样开100线程去爬100页面的详情页面,因为fang.com只能看100页
        t=threading.Thread(target=fang_com,args=(‘http://esf.sz.fang.com/house/i3%s‘%i,))           ###这样做没问题,但如果你是爬取1000页面,也这样做就不合适了,python开多了线程会导致线程创建失败,100线程已经很快了,网速是瓶颈了这时候,我开100线程时候网速是800KB左右的网速,我宽带才4M,运营商还算比较良心了,4M宽带400k

        threads.append(t)

        t.start()

    for t in threads:
        t.join()

    print ‘over‘

发下运行结果:

时间: 2024-09-29 12:11:13

介绍requests+threading多线程爬虫,提取采用xpath 和正则两种,介绍线程锁的相关文章

提取登录的Token值两种方法之正则表达式和Json提取器

Hello everyBody, 今天我讲一下,提取登录的Token值得两种方式, 其实很简单: 类似于这样的token值怎么提取呢 1. 正则表达式,我个人比较喜欢用正则表达式 直接"access_token": "(.*?)" 正规则表达式:{“access_token”:"(.*?)"}(note:*号也可以换成+号,一样的效果)   ():封装了待返回的匹配字符串. .:匹配任何单个字符串. *:一次或多次. ?:在找到第一个匹配项后停止

采用java和数据库两种方式进行加锁

java代码加锁 publicstatic synchronized int generate(StringtableName){Stringsql = "select value from t_table_id where table_name=?";Connectionconn = null;PreparedStatementpstmt = null;ResultSetrs = null;intvalue = 0;try{conn= DbUtil.getConnection();p

多线程实现Thread.Start()与ThreadPool.QueueUserWorkItem两种方式对比

Thread.Start(),ThreadPool.QueueUserWorkItem都是在实现多线程并行编程时常用的方法.两种方式有何异同点,而又该如何取舍? 写一个Demo,分别用两种方式实现.观察各自的现象. 一个WorkMan class,其内的method doSomething()是每次异步线程调用的方法.该方法只是随机的让线程休眠一段时间. 1 public void doSomething() 2 { 3 OnBegin(new EventArgs()); 4 5 // some

Python每日一练(2):找出html中的所有链接(Xpath、正则两个版本)

要在hrml文件中找出特定的内容,首先需要观察该内容是什么东西,在什么位置,这样才能找出来. 假设html的文件名称是:"1.html".href属性全都在a标签里. 正则版: #coding:utf-8 import re with open('1.html','r') as f: data = f.read() result = re.findall(r'href="(.*?)"',data) for each in result: print each Xpa

java 实现多线程的两种方式

一.问题引入 说到这两个方法就不得不说多线程,说到多线程就不得不提实现多线程的两种方式继承Thread类和实现Runable接口,下面先看这两种方式的区别. 二. Java中实现多线程的两种方式 1.  继承Thread类 /** * 使用Thread类模拟4个售票窗口共同卖100张火车票的程序,实际上是各卖100张 */ public class ThreadTest { public static void main(String[] args){ new MyThread().start(

iOS 多线程之线程锁Swift-Demo示例总结

线程锁是什么 在前面的文章中总结过多线程,总结了多线程之后,线程锁也是必须要好好总结的东西,这篇文章构思的时候可能写的东西得许多,只能挤时间一点点的慢慢的总结了,知道了线程之后要了解线程锁就得先了解一下什么是“线程锁”. “线程锁”一段代码在同一个时间内是只能被一个线程访问的,为了避免在同一时间内有多个线程访问同一段代码就有了“锁”的概念,比如说,线程A在访问着一段代码,进入这段代码之后我们加了一个“锁”.这个时候线程B又来访问了,由于有了锁线程B就会等待线程A访问结束之后解开了“锁”线程B就可

Requests爬虫和scrapy框架多线程爬虫

1.基于Requests和BeautifulSoup的单线程爬虫 1.1 BeautifulSoup用法总结 1. find,获取匹配的第一个标签 tag = soup.find('a') print(tag) tag = soup.find(name='a', attrs={'class': 'sister'}, recursive=True, text='Lacie') tag = soup.find(name='a', class_='sister', recursive=True, te

Python多线程爬虫爬取电影天堂资源

最近花些时间学习了一下Python,并写了一个多线程的爬虫程序来获取电影天堂上资源的迅雷下载地址,代码已经上传到GitHub上了,需要的同学可以自行下载.刚开始学习python希望可以获得宝贵的意见. 先来简单介绍一下,网络爬虫的基本实现原理吧.一个爬虫首先要给它一个起点,所以需要精心选取一些URL作为起点,然后我们的爬虫从这些起点出发,抓取并解析所抓取到的页面,将所需要的信息提取出来,同时获得的新的URL插入到队列中作为下一次爬取的起点.这样不断地循环,一直到获得你想得到的所有的信息爬虫的任务

python多线程爬虫+批量下载斗图啦图片项目(关注、持续更新)

python多线程爬虫项目() 爬取目标:斗图啦(起始url:http://www.doutula.com/photo/list/?page=1) 爬取内容:斗图啦全网图片 使用工具:requests库实现发送请求.获取响应. xpath实现数据解析.提取和清洗 threading模块实现多线程爬虫 爬取结果: 思路:由于该爬虫存在网络密集IO和磁盘密集IO,存在大量等待时间,遂采用多线程方式爬取. 设计:本文采用多为结构化代码的面向对象封装设计思路,使用生产消费者模型,完成多线程的调度.爬取.