|
|
|
|
@ -1958,7 +1958,7 @@ class FacultyListHtmlAdapter implements CrawlerAdapterInterface
|
|
|
|
|
$lead = is_array($item->extra['lead_author'] ?? null) ? $item->extra['lead_author'] : [];
|
|
|
|
|
$changed = false;
|
|
|
|
|
|
|
|
|
|
if (empty($lead['academic_title'])) {
|
|
|
|
|
if (empty($lead['academic_title']) || ! $this->looksLikeAcademicTitle((string) $lead['academic_title'])) {
|
|
|
|
|
$title = $this->extractAcademicTitleFromProfileHtml($html);
|
|
|
|
|
if ($title !== null && $title !== '') {
|
|
|
|
|
$lead['academic_title'] = $title;
|
|
|
|
|
@ -2055,27 +2055,65 @@ class FacultyListHtmlAdapter implements CrawlerAdapterInterface
|
|
|
|
|
|
|
|
|
|
protected function extractAcademicTitleFromProfileHtml(string $html): ?string
|
|
|
|
|
{
|
|
|
|
|
if (preg_match('/<em>\s*([^<]+?)\s*<\/em>/u', $html, $titleMatch)) {
|
|
|
|
|
// 电院等:<div class="tit"><p>姓名</p><span>教授</span></div>
|
|
|
|
|
if (preg_match('#<div class="tit"[^>]*>\s*<p>[^<]+</p>\s*<span>\s*([^<]+?)\s*</span>#su', $html, $match)) {
|
|
|
|
|
$title = CrawlAuthorParser::cleanText($match[1]);
|
|
|
|
|
if ($this->looksLikeAcademicTitle((string) $title)) {
|
|
|
|
|
return $title;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 材料学院等:<div class="people-name"><p>姓名</p><em>教授</em></div>
|
|
|
|
|
if (preg_match('#<(?:div|p)[^>]*class="[^"]*people-name[^"]*"[^>]*>.*?<em>\s*([^<]+?)\s*</em>#su', $html, $titleMatch)) {
|
|
|
|
|
$title = CrawlAuthorParser::cleanText($titleMatch[1]);
|
|
|
|
|
if ($title !== null && $title !== '') {
|
|
|
|
|
if ($this->looksLikeAcademicTitle((string) $title)) {
|
|
|
|
|
return $title;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (['职称', '职务'] as $label) {
|
|
|
|
|
$title = $this->parseLabeledField($html, $label);
|
|
|
|
|
if ($title !== null && $title !== '') {
|
|
|
|
|
if ($this->looksLikeAcademicTitle((string) $title)) {
|
|
|
|
|
return $title;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (preg_match('#<div class="tit"[^>]*>.*?<span>([^<]+)</span>#su', $html, $match)) {
|
|
|
|
|
return CrawlAuthorParser::cleanText($match[1]);
|
|
|
|
|
if (preg_match_all('/<em>\s*([^<]+?)\s*<\/em>/u', $html, $ems)) {
|
|
|
|
|
foreach ($ems[1] as $candidate) {
|
|
|
|
|
$title = CrawlAuthorParser::cleanText($candidate);
|
|
|
|
|
if ($this->looksLikeAcademicTitle((string) $title)) {
|
|
|
|
|
return $title;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (preg_match('#<div class="tit"[^>]*>.*?<span>\s*([^<]+?)\s*</span>#su', $html, $match)) {
|
|
|
|
|
$title = CrawlAuthorParser::cleanText($match[1]);
|
|
|
|
|
if ($this->looksLikeAcademicTitle((string) $title)) {
|
|
|
|
|
return $title;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function looksLikeAcademicTitle(?string $title): bool
|
|
|
|
|
{
|
|
|
|
|
$title = trim((string) $title);
|
|
|
|
|
if ($title === '' || mb_strlen($title) > 30) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (preg_match('/首页|导航|菜单|返回|更多|搜索|登录|关于/u', $title)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (bool) preg_match(
|
|
|
|
|
'/教授|副教授|讲师|助教|研究员|副研究员|助理研究员|工程师|院士|博导|导师|专家|学者|长聘|准聘|特聘|兼职|访问|青年|副高|正高|中级|初级/u',
|
|
|
|
|
$title,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function extractPhoneFromProfileHtml(string $html): ?string
|
|
|
|
|
{
|
|
|
|
|
$scoped = $this->profileContentHtml($html);
|
|
|
|
|
|