网页数据抓取怎么写(Python多线程抓取数据(一)|本篇)
优采云 发布时间: 2022-02-10 15:19网页数据抓取怎么写(Python多线程抓取数据(一)|本篇)
我会多方面讲解大数据职业学习的理论,做到最好的文章讲解。感谢您的赞赏。[本文文章转载于博客园:susmote]。评论要求博主转发。
在这篇文章文章中,我们主要介绍多线程数据捕获。
多线程以并发方式执行。这里需要注意的是,Python中的多线程程序只能以并发的方式在单核上运行,即使在多核机器上也是如此。因此,使用多线程抓取可以极大的提高抓取效率
接下来我们以requests为例介绍多线程爬取,然后和单线程程序进行对比,体验多线程效率的提升
我们通过当当网测试了我们的多线程实例,并演示了搜索结果同爬的功能。搜索方式地址如下
1
可以看到key代表搜索关键字,act代表你是怎么搜索的,page_index代表搜索页面的页码
抓取上述页码后,提取其中的信息,最后将提取的信息保存在一个文本文件中,其中保存了每本书的标题及其链接
下面我们定义抓取实验所需的方法(或函数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
二十三
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 编码=utf-8
__Author__ =“支持”
导入请求
从 bs4 导入 BeautifulSoup
但还是不得不说博主真的很不错!
def format_str(s):
返回 s.replace("\n", "").replace(" ", "").replace("\t", "")
def get_urls_in_pages(from_page_num, to_page_num):
网址 = []
search_word = "蟒蛇"
url_part_1 = ""
url_part_2 = "&act=输入"
url_part_3 = "&page_index="
对于我在范围内(from_page_num,to_page_num + 1):
urls.append(url_part_1 + search_word + url_part_2 + url_part_3 + str(i))
all_href_list = []
对于网址中的网址:
打印(网址)
resp = requests.get(url)
bs = BeautifulSoup(resp.text, "lxml")
a_list = bs.find_all("a")
需要列表 = []
对于 a_list 中的一个:
如果 a.attrs 中的“名称”:
name_val = a['name']
href_val = a['href']
标题 = a.文本
如果 name_val 和 title 中的 'itemlist-title' ! = "":
如果 [title, href_val] 不在 required_list 中:
required_list.append([format_str(title), format_str(href_val)])
all_href_list += required_list
all_href_file = open(str(from_page_num) + '_' + str(to_page_num) + '_' + 'all_hrefs.txt', 'w')
对于 all_href_list 中的 href:
all_href_file.write('\t'.join(href) + '\n')
all_href_file.close()
打印(from_page_num,to_page_num,len(all_href_list))
下面解释一下代码
首先,format_str用于提取信息后去除多余的空格
get_url_in_pages 方法是执行函数的主体。该方法接收的参数是指页码的范围。在函数体中,urls主要用于存储根据这两个参数生成的所有待爬取页面的链接。我把url分成3部分也是为了方便后面的链接组合,然后for循环就是做拼接的工作。我不会在这里解释它。如果不明白,请留言。
接下来,我们定义一个列表all_href_list,这个列表用来存放每一页收录的书籍信息,实际上是一个嵌套列表,里面的元素是[书名,链接],他的形式如下图
1
2
3
4
5
6
all_href_list = [
['标题1',“链接1”],
['标题2',“链接2”],
['标题 3',“链接 3”],
……
]
这文章我达不到这个水平
下面的代码是从一个页面爬取和提取信息。这部分代码在for url in urls的循环体中,先打印链接,然后调用requs的get方法获取页面,再使用BeautifulSoup获取页面。将get请求返回的HTML文本进行分析,转换成BeautifulSoup可以处理的结构,命名为bs
之后,我们定义的needed_list用来存放书名和链接。bs.find_all('a') 提取页面中的所有链接元素,for a in a_list 遍历并分析每个列表中的元素。在此之前,我们通过浏览器找到了他的结构。
每个书本元素都有一个值为“itemlist_title”的属性名称。通过这个,我们可以很方便的过滤出书本元素,然后将书本信息和链接元素href一起存储到列表中。在它存在之前,我们也做一些判断,这个链接是否已经存在,有这个元素的链接是否为空
一个页面的每个链接提取出来后,可以添加到all_href_list,也就是下面这行代码
1
all_href_list += required_list
注意我在这里使用 += 运算符
获取范围内的所有链接元素后,您可以写入文件。我不会在这里过多解释。
那么我们下一步就是定义多线程了,因为我们搜索关键词的总页数是32页
所以这里我们要用3个线程来完成这些任务,也就是每个线程处理10个页面。在单线程的情况下,这30页是一个线程单独完成的
下面我们给出爬取方案的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
二十三
24
25
26
27
28
29
# 编码=utf-8
__Author__ =“支持”
哎,刷一波存在
*敏*感*词*时间
导入线程
从 Mining_func 导入 get_urls_in_pages
def multiple_threads_test():
start_time = time.time()
page_range_list = [
(1, 10),
(11, 20),
(21, 32),
]
th_list = []
对于 page_range_list 中的 page_range:
th = threading.Thread(target = get_urls_in_pages, args = (page_range[0], page_range[1]))
th_list.append(th)
对于 th_list 中的 th:
th.start()
对于 th_list 中的 th:
th.join()
end_time = time.time()
print("总使用时间 1:", end_time - start_time)
返回结束时间 - 开始时间
简单解释一下,为了得到运行时间,我们定义了一个开始时间start_time和一个结束时间end_time,运行时间就是结束时间减去开始时间
然后定义一个列表page_range_list,将页码分成三段,如前所述
之后定义了一个列表th_list,它是所有线程对象的列表,然后通过循环生成三个线程对象,分别对应不同的页码范围,并存储在列表中。
然后在下面的循环中,分别执行th.start()来启动线程。在后者中,我们退出函数是为了让这些异步并发执行的线程全部执行,这里我们使用线程的join方法等待每个线程执行。完全的
现在是测试代码最激动人心的时刻
在这里,我们编写如下代码
1
2
3
4
5
6
7
8
# 编码=utf-8
__Author__ =“支持”
我又喘不过气来了
从 Mining_threading 导入 multiple_threads_test
如果 __name__ == "__main__":
mt = multiple_threads_test()
打印(“吨”,吨)
为了使测试结果更加准确,我们进行了三个实验,取平均时间
第一次实验
使用时间6.651
第二次实验
使用时间6.876
第三次实验
使用时间6.960
平均时间如下
6.829
下面是单进程代码
1
2
3
4
5
6
7
8
9
10
11
12
13
# 编码=utf-8
__Author__ =“支持”
*敏*感*词*时间
从 Mining_func 导入 get_urls_in_pages
你觉得 文章 很棒吗
def sigle_test():
start_time = time.time()
get_urls_in_pages(1, 32)
end_time = time.time()
print("总使用时间:", end_time - start_time)
返回结束时间 - 开始时间
调用函数如下
1
2
3
4
5
6
7
8
9
# 编码=utf-8
__Author__ =“支持”
从 single_mining 导入 single_test
不火就受不了了吗?
如果 __name__ == "__main__":
st = single_test()
打印('st',st)
在命令行执行
第一次
10.138
第二次
10.290
第三次
10.087
平均花费时间
10.171
所以,多线程确实可以提高爬取的效率。请注意,这是在数据相对较小时完成的。如果数据量比较大,多线程的优势就很明显了。
你可以自己改搜索关键词,和页码,或者找一个新的网页(爬也跟网速有很大关系)
附上几张捕获数据的图片
像往常一样,如果你想知道如何学习大数据,可以私聊我,每次你的认可都是对我很大的鼓励。