php多线程抓取多个网页(一个IT业滚爬了多年的程序员,对这样的搜索结果很不满意)
优采云 发布时间: 2022-03-16 01:14php多线程抓取多个网页(一个IT业滚爬了多年的程序员,对这样的搜索结果很不满意)
最近在长沙找工作,就通过湖南人才市场找工作。结果数据让我很难比较,作为一个在IT行业工作多年的程序员,我对这样的搜索结果很不满意。所以,我不得不自己组织数据。本文内容包括:网页数据爬取、网页数据分析、数据挖掘、python多线程、多进程应用等专题。
先说结论
首先给出上面的*敏*感*词*,从图中可以得出以下结论:
当然,也可以挖掘出更多的有效信息。比如按薪水排名的职位:
这样,我可以快速找到长沙目前的高薪职位和要求。这就是成为程序员的好处^_^。下面将介绍数据采集和数据分析。
数据抓取
我写了一个 crawler.py 程序。内容如下:
# -*- coding: utf-8 -*-
import sys, os, re
import http.client
import threading
import time
ids = []
# 生成要抓取的职位列表ID
def generate_list_ids():
global ids
for i in range(1, 77):
ids.append(i)
# 生成要抓取的职位详情ID
def generate_detail_ids():
global ids
for i in range(1, 77):
f = open(str(i)+'.lst', 'r', encoding='gbk')
s = f.read(1024000)
inputs = re.findall(r"", s)
for inp in inputs:
m = re.match(r".*value='(.*)'", inp)
ids.append(m.group(1))
f.close()
# 用多线程的方式抓取,单线程太慢了
class Crawler(threading.Thread):
def __init__(self, islist=True):
self.h = http.client.HTTPConnection('www.hnrcsc.com')
self.islist = islist
threading.Thread.__init__(self)
# 抓取到的网页,将它存入文件
def write_file(self, filename):
o = open(filename, 'wb')
o.write(self.h.getresponse().read(1024000))
o.close()
# 抓取职位列表
def get_list(self, cid):
self.h.request('POST', '/Search/searchResult.asp?pagenum='+str(cid), 'flag=0&wkregion=430100&keywordtype=&postypesub=&postypemain=0100&keyword=%C7%EB%CA%E4%C8%EB%B9%D8%BC%FC%D7%D6&during=90&pagenum='+str(cid), {
'Content-Type': 'application/x-www-form-urlencoded'})
self.write_file(str(cid)+'.lst')
def get_detail(self, cid):
try:
self.h.request('GET', '/jobs/posFiles/showPosDetail.asp?posid='+str(cid))
self.write_file(str(cid)+'.det')
except:
print(cid)
self.h.close()
time.sleep(3)
self.h = http.client.HTTPConnection('www.hnrcsc.com')
def run(self):
global ids
cid = ids.pop() if len(ids)>0 else None
while cid:
if self.islist:
self.get_list(cid)
else:
self.get_detail(cid)
cid = ids.pop() if len(ids)>0 else None
print(self.name + ' Finished!')
self.h.close()
if len(sys.argv) != 2:
print('''Usage: crawler.py command
list: get list
detail: get detail
clean: clean all webpage
''')
exit()
if sys.argv[1] == 'detail': # 抓取职位详情
generate_detail_ids()
for i in range(50):
Crawler(False).start()
elif sys.argv[1] == 'list': # 抓取职位列表
generate_list_ids()
for i in range(10):
Crawler().start()
elif sys.argv[1] == 'clean': # 删除所有抓取到的文件
os.system('del *.lst')
os.system('del *.det')
else:
print('''Usage: crawler.py command
list: get list
detail: get detail
clean: clean all webpage
''')
以上是最终程序。正如《黑客与画家》中提到的,编写程序是一个类似于绘画的过程。这是可用的半成品。我将大致描述完成这个程序的过程:
使用http.client获取一个网页的数据,可以快速了解http.client的用法使用for循环获取2个页面的数据,测试http.client多次取数据的情况,把完成将内容放入一个方法(get_list)中,编写一个读取文件使用,并使用正则表达式提取作业详情ID的所有代码。测试通过后,注释掉这部分代码,使用http.client获取一个job details的数据,总结三个内容,就可以得到一个单线程的网页爬虫程序
我跑了这个程序,然后出去吃饭。回来的时候看到还没写完,就看了一下python多线程的内容,改成多线程代码,加了一些容错处理。, 完成。
数据分析
数据分析其实就是从作业列表文件和作业明细文件中获取有效信息,放入关系数据库,然后利用关系数据库强大的查询语句,获取重要信息。数据分析的关键其实就是用正则表达式匹配关键数据部分。下面是我写的passer.py代码
<p># -*- encoding: utf-8 -*-
import re, sqlite3, multiprocessing
class Passer(multiprocessing.Process):
def __init__(self, ids, datas):
self.ids = ids
self.datas = datas
multiprocessing.Process.__init__(self)
# 获取职位详情数据
def get_detail(self, fid):
f = open(str(fid)+'.det', 'r', encoding='gbk')
s = f.read(1024000)
out = re.match(r'''.*招聘人数.*.*人 .*/firstpage/ima/diand.gif 发布日期.*(.*) .*.*招聘部门.*(.*) .*截止日期.*(.*) .*发布单位.*target="_blank">(.*)</a> .*工作方式.*(.*) .*最低*敏*感*词*要求.*(.*) .*工作地区.*(.*) .*薪酬待遇.*(.*) .*.*详细待遇.*class="zhongxia2" colspan="3" align="left" >(.*) .*联系电话.*(.*) .*电子邮件.*(.*) .*联 系 人.*class="zhongxia2" >(.*) .*通讯地址.*(.*?) .*岗位描述.*(.*).*岗位要求.*(.*).* ''', s, re.S)
if not out:
out = re.match(r'''.*招聘人数.*.*人 .*/firstpage/ima/diand.gif 发布日期.*(.*) .*.*招聘部门.*(.*) .*截止日期.*(.*) .*发布单位.*target="_blank">(.*)</a> .*工作方式.*(.*) .*最低*敏*感*词*要求.*(.*) .*工作地区.*(.*) .*详细待遇.*class="zhongxia2" colspan="3" align="left" >(.*) .*联系电话.*(.*) .*电子邮件.*(.*) .*联 系 人.*class="zhongxia2" >(.*) .*通讯地址.*(.*?) .*岗位描述.*(.*).*岗位要求.*(.*).* ''', s, re.S)
f.close()
return out.groups()
# 处理职位列表
def handle_file(self, fileid):
global datas
f = open(str(fileid)+'.lst', 'r', encoding='gbk')
a = re.findall('