爬虫技术:携程爬虫阳光问政数据

携程爬取阳光问帖子:进行了简单的数据存储,数据量共145226条,爬取时间为:3.65小时,时间感觉要多于这个时间。

代码如下:

import time
import gevent
import re
import lxml
import lxml.etree
import requests
import chardet


def get_url_list(url):
    resp = requests.get(url)
    # 获取网页的编码格式,但是gb2312不能编码解码字节类型,只能换成gbk
    code_sytle = chardet.detect(resp.content)
    html_str = resp.content.decode("gbk")
    e = lxml.etree.HTML(html_str)
    count_str = e.xpath("//div[@class='pagination']/text()")[-1]
    # 获取帖子数量
    count = re.findall("(\d+)", count_str)[0]
    # 获取有多少页
    page_count = int(count) // 30
    url_list = list()
    for i in range(0, page_count + 1):
        url_list.append(url.format(i * 30))
    return url_list


def get_per_page_info(url_list, f):
    for url in url_list:
        try:
            resp = requests.get(url=url,timeout=10)  # 此处容易出现长时间等待,因此加上超时设置
            html_str = resp.content.decode("gbk",errors="ignore")  # 此处容易出现解码错误,因此加上 erros="ignore"
            e = lxml.etree.HTML(html_str)
            tr_list = e.xpath("//div[@class='greyframe']//table[2]//table//tr")
            info_str = ""
            for tr in tr_list:
                serial_num = tr.xpath(".//td[1]/text()")[0]
                info_str += serial_num
                info_str += " "
                request_type = tr.xpath(".//td[2]//a[1]/text()")[0]
                info_str += request_type
                info_str += " "
                request_reason = tr.xpath(".//td[2]//a[2]/text()")[0]
                info_str += request_reason
                info_str += " "
                duty_department = tr.xpath(".//td[2]//a[3]/text()")[0]
                info_str += duty_department
                info_str += " "
                status = tr.xpath(".//td[3]//span/text()")[0]
                info_str += status
                info_str += " "   
                person = tr.xpath(".//td[4]/text()")   # 测试的过程中,此处容易越界,因此加入判断。
                if len(person) == 0:
                    person = "MISS"
                    info_str += person
                else:
                    person = tr.xpath(".//td[4]/text()")[0]
                    info_str += person
                info_str += " "
                time = tr.xpath(".//td[5]/text()")[0]
                info_str += time
                info_str += "\r\n "
            print(info_str)
            f.write(info_str)

        except Exception as e:
            print(e)

if __name__ == '__main__':
    t = time.time()
    url = "http://wz.sun0769.com/index.php/question/report?page={}"
    url_list = get_url_list(url)
    f = open("sun_info.txt", "w", encoding="utf-8")
    # 任务切割,让10个携程去执行任务,每个携程传递url_list的一部分数据。
    xclist = [[], [], [], [], [], [], [], [], [], []]
    N = len(xclist)
    task_list = list()
    for i in range(len(url_list)):
        xclist[i % N].append(url_list[i])
    for i in range(N):
        task_list.append(gevent.spawn(get_per_page_info, xclist[i], f))

    gevent.joinall(task_list)
    f.close()
    print(time.time() - t)


# 13162.275838851929 执行时间

复习协程的知识:

多线程会抢抢夺公共资源,因此会造成公共资源的不安全,需要通过线程锁进行解决,那么多个携程为什么不存在这个情况呢?

因为多个协程也是在一个线程里面进行运行,只是在遇到IO堵塞操作时候,会自动切换到其他协程,让它们进行工作,此案例中,写入文件是一个IO操作,当一个协程写入文件时阻塞时,立马切换到其他协程进行数据的请求和筛选,合适的时机,在切换(此时应该是用到了上下文了,记录了数据写到哪里被阻塞了,切换回来继续在此处写入,这里概念比较模糊 # TODO 需要继续研究)到刚才读写操作的协程,进行数据写入。

猜你喜欢

转载自www.cnblogs.com/meloncodezhang/p/11443580.html